From 2d0c3f5c5b10d3ee3ef601b4e0c2d8e564d62830 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Thu, 5 Feb 2026 12:50:05 +0100 Subject: [PATCH 01/15] refactor(Controller): Modernize code - Use getFirstNodeById for performance reason - Add typing - Use property contrustor promotion - Use attributes instead of annotations Signed-off-by: Carl Schwan --- lib/Controller/ContactsController.php | 215 ++++++---------------- lib/Controller/FavoritesController.php | 138 ++++++-------- lib/Controller/PhotosController.php | 91 ++++----- lib/Controller/PublicPageController.php | 9 +- lib/Controller/PublicTracksController.php | 209 +++++++++------------ lib/Controller/UtilsController.php | 58 +++--- lib/Hooks/FileHooks.php | 41 ++--- lib/Service/GeophotoService.php | 102 +++------- lib/Service/PhotofilesService.php | 34 ++-- lib/Service/TracksService.php | 56 +++--- 10 files changed, 350 insertions(+), 603 deletions(-) diff --git a/lib/Controller/ContactsController.php b/lib/Controller/ContactsController.php index 4916b79f6..cc7c0a499 100644 --- a/lib/Controller/ContactsController.php +++ b/lib/Controller/ContactsController.php @@ -15,10 +15,14 @@ use OCA\DAV\CardDAV\CardDavBackend; use OCA\Maps\Service\AddressService; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\DataDisplayResponse; use OCP\AppFramework\Http\DataResponse; use OCP\Contacts\IManager; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Files\File; +use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\Node; use OCP\Files\NotFoundException; @@ -30,66 +34,38 @@ use Sabre\VObject\Reader; class ContactsController extends Controller { - private $userId; - private $contactsManager; - private $addressService; - private $dbconnection; - private $cdBackend; - private $avatarManager; - private $root; - private $urlGenerator; - private $geoDistanceMax; // Max distance in meters to consider that 2 addresses are the same location + private int $geoDistanceMax = 5; // Max distance in meters to consider that 2 addresses are the same location - /** - * @param $AppName - * @param IRequest $request - * @param IDBConnection $dbconnection - * @param IManager $contactsManager - * @param AddressService $addressService - * @param $UserId - * @param CardDavBackend $cdBackend - * @param IAvatarManager $avatarManager - * @param IRootFolder $root - */ public function __construct( - $AppName, + string $appName, IRequest $request, - IDBConnection $dbconnection, - IManager $contactsManager, - AddressService $addressService, - $UserId, - CardDavBackend $cdBackend, - IAvatarManager $avatarManager, - IRootFolder $root, - IURLGenerator $urlGenerator) { - parent::__construct($AppName, $request); - $this->userId = $UserId; - $this->avatarManager = $avatarManager; - $this->contactsManager = $contactsManager; - $this->addressService = $addressService; - $this->dbconnection = $dbconnection; - $this->cdBackend = $cdBackend; - $this->root = $root; - $this->urlGenerator = $urlGenerator; - $this->geoDistanceMax = 5; + private IDBConnection $dbconnection, + private IManager $contactsManager, + private AddressService $addressService, + private string $userId, + private CardDavBackend $cdBackend, + private IAvatarManager $avatarManager, + private IRootFolder $root, + private IURLGenerator $urlGenerator, + ) { + parent::__construct($appName, $request); } /** * Converts a geo string as a float array - * @param string formatted as "lat;lon" + * @param string $geo formatted as "lat;lon" * @return float[] array containing [lat;lon] */ - private function geoAsFloatArray($geo) { - $res = array_map(function ($value) {return floatval($value);}, explode(';', $geo)); - return $res; + private function geoAsFloatArray(string $geo): array { + return array_map(static fn ($value): float => floatval($value), explode(';', $geo)); } /** * check if geographical address is duplicated - * @param array containing contact's previous different addresses - * @param contact's address to check + * @param list containing contact's previous different addresses + * @param array $geo contact's address to check * @return integer : -1 if address is new, index of duplicated address in other cases */ - private function isNewAddress($prevGeo, $geo) { + private function isNewAddress(array $prevGeo, array $geo): int { if (empty($geo)) { // Address not converted to geo coords return -1; } @@ -123,23 +99,20 @@ private function getDistance(array $coordsA, array $coordsB) { $earthRadius = 6378137; // in m $dlon = ($lonB - $lonA) / 2; $dlat = ($latB - $latA) / 2; - $a = (sin($dlat) * sin($dlat)) + cos($latA) * cos($latB) * (sin($dlon) * sin($dlon - )); + $a = (sin($dlat) * sin($dlat)) + cos($latA) * cos($latB) * (sin($dlon) * sin($dlon)); $d = 2 * atan2(sqrt($a), sqrt(1 - $a)); return $d * $earthRadius; } /** - * get contacts with coordinates + * Get contacts with coordinates * - * @NoAdminRequired - * @param null $myMapId - * @return DataResponse * @throws \OCP\Files\NotPermittedException * @throws \OC\User\NoUserException */ - public function getContacts($myMapId = null): DataResponse { - if (is_null($myMapId) || $myMapId === '') { + #[NoAdminRequired] + public function getContacts(?int $myMapId = null): DataResponse { + if (is_null($myMapId)) { $contacts = $this->contactsManager->search('', ['GEO', 'ADR'], ['types' => false]); $addressBooks = $this->contactsManager->getUserAddressBooks(); $result = []; @@ -248,16 +221,15 @@ public function getContacts($myMapId = null): DataResponse { //Fixme add contacts for my-maps $result = []; $userFolder = $this->root->getUserFolder($this->userId); - $folders = $userFolder->getById($myMapId); - if (empty($folders)) { - return new DataResponse($result); - } - $folder = array_shift($folders); - if ($folder === null) { + $folder = $userFolder->getFirstNodeById($myMapId); + if (!($folder instanceof Folder)) { return new DataResponse($result); } $files = $folder->search('.vcf'); foreach ($files as $file) { + if (!($file instanceof File)) { + continue; + } // $cards = explode("END:VCARD\r\n", $file->getContent()); $cards = [$file->getContent()]; foreach ($cards as $card) { @@ -311,12 +283,7 @@ public function getContacts($myMapId = null): DataResponse { } } - /** - * @param $contactUid - * @param $addressBookUri - * @return string - */ - private function directUrlToContact($contactUid, $addressBookUri) { + private function directUrlToContact(string $contactUid, string $addressBookUri): string { return $this->urlGenerator->getAbsoluteURL( $this->urlGenerator->linkToRoute('contacts.contacts.direct', [ 'contact' => $contactUid . '~' . $addressBookUri @@ -325,7 +292,6 @@ private function directUrlToContact($contactUid, $addressBookUri) { } /** - * @param Node $file * @param \Sabre\VObject\Document $vcard * @param string $geo * @param string|null $adrtype @@ -390,12 +356,9 @@ private function N2FN(string $n): ?string { } /** - * get all contacts - * - * @NoAdminRequired - * @param string $query - * @return DataResponse + * Get all contacts */ + #[NoAdminRequired] public function searchContacts(string $query = ''): DataResponse { $contacts = $this->contactsManager->search($query, ['FN'], ['types' => false]); $booksReadOnly = $this->getAddressBooksReadOnly(); @@ -425,30 +388,13 @@ public function searchContacts(string $query = ''): DataResponse { } /** - * @NoAdminRequired - * @param string $bookid - * @param string $uri - * @param string $uid - * @param float|null $lat - * @param float|null $lng - * @param string $attraction - * @param string $house_number - * @param string $road - * @param string $postcode - * @param string $city - * @param string $state - * @param string $country - * @param string $type - * @param string|null $address_string - * @param int|null $fileId - * @param int|null $myMapId - * @return DataResponse * @throws \OCP\DB\Exception * @throws \OCP\Files\NotPermittedException * @throws \OC\User\NoUserException */ + #[NoAdminRequired] public function placeContact( - string $bookid, + int $bookid, string $uri, string $uid, ?float $lat, @@ -476,7 +422,7 @@ public function placeContact( if ($lat !== null && $lng !== null) { // we set the geo tag if (!$attraction && !$house_number && !$road && !$postcode && !$city && !$state && !$country && !$address_string) { - $result = $this->contactsManager->createOrUpdate(['URI' => $uri, 'GEO' => $lat . ';' . $lng], $bookid); + $result = $this->contactsManager->createOrUpdate(['URI' => $uri, 'GEO' => $lat . ';' . $lng], (string)$bookid); } // we set the address elseif (!$address_string) { @@ -506,7 +452,7 @@ public function placeContact( } else { // TODO find out how to remove a property // following does not work properly - $result = $this->contactsManager->createOrUpdate(['URI' => $uri, 'GEO' => null], $bookid); + $result = $this->contactsManager->createOrUpdate(['URI' => $uri, 'GEO' => null], (string)$bookid); } return new DataResponse('EDITED'); } else { @@ -515,17 +461,14 @@ public function placeContact( } } else { $userFolder = $this->root->getUserFolder($this->userId); - $folders = $userFolder->getById($myMapId); - if (empty($folders)) { - return new DataResponse('MAP NOT FOUND', 404); - } - $mapsFolder = array_shift($folders); - if (is_null($mapsFolder)) { + $mapsFolder = $userFolder->getFirstNodeById($myMapId); + if (!($mapsFolder instanceof Folder)) { return new DataResponse('MAP NOT FOUND', 404); } if (is_null($fileId)) { $card = $this->cdBackend->getContact($bookid, $uri); try { + /** @var File $file */ $file = $mapsFolder->get($uri); } catch (NotFoundException $e) { if (!$mapsFolder->isCreatable()) { @@ -534,12 +477,8 @@ public function placeContact( $file = $mapsFolder->newFile($uri); } } else { - $files = $mapsFolder->getById($fileId); - if (empty($files)) { - return new DataResponse('CONTACT NOT FOUND', 404); - } - $file = array_shift($files); - if (is_null($file)) { + $file = $mapsFolder->getFirstNodeById($fileId); + if (!($file instanceof File)) { return new DataResponse('CONTACT NOT FOUND', 404); } $card = $file->getContent(); @@ -582,28 +521,20 @@ public function placeContact( } /** - * @NoAdminRequired - * @param string $bookid - * @param string $uri - * @param int $myMapId - * @param int|null $fileId - * @return DataResponse|void * @throws \OCP\Files\NotPermittedException * @throws \OC\User\NoUserException */ - public function addContactToMap(string $bookid, string $uri, int $myMapId, ?int $fileId = null): DataResponse { + #[NoAdminRequired] + public function addContactToMap(int $bookid, string $uri, int $myMapId, ?int $fileId = null): DataResponse { $userFolder = $this->root->getUserFolder($this->userId); - $folders = $userFolder->getById($myMapId); - if (empty($folders)) { - return new DataResponse('MAP NOT FOUND', 404); - } - $mapsFolder = array_shift($folders); - if (is_null($mapsFolder)) { + $mapsFolder = $userFolder->getFirstNodeById($myMapId); + if (!($mapsFolder instanceof Folder)) { return new DataResponse('MAP NOT FOUND', 404); } if (is_null($fileId)) { $card = $this->cdBackend->getContact($bookid, $uri); try { + /** @var File $file */ $file = $mapsFolder->get($uri); } catch (NotFoundException $e) { if (!$mapsFolder->isCreatable()) { @@ -612,12 +543,8 @@ public function addContactToMap(string $bookid, string $uri, int $myMapId, ?int $file = $mapsFolder->newFile($uri); } } else { - $files = $mapsFolder->getById($fileId); - if (empty($files)) { - return new DataResponse('CONTACT NOT FOUND', 404); - } - $file = array_shift($files); - if (is_null($file)) { + $file = $mapsFolder->getFirstNodeById($fileId); + if (!($file instanceof File)) { return new DataResponse('CONTACT NOT FOUND', 404); } $card = $file->getContent(); @@ -630,16 +557,13 @@ public function addContactToMap(string $bookid, string $uri, int $myMapId, ?int $file->putContent($vcard->serialize()); return new DataResponse('DONE'); } + return new DataResponse('CONTACT NOT FOUND', 404); } - /** - * @param string $bookid - * @return bool - */ - private function addressBookIsReadOnly(string $bookid): bool { + private function addressBookIsReadOnly(int $bookid): bool { $userBooks = $this->cdBackend->getAddressBooksForUser('principals/users/' . $this->userId); foreach ($userBooks as $book) { - if ($book['id'] === (int)$bookid) { + if ($book['id'] === $bookid) { return (isset($book['{http://owncloud.org/ns}read-only']) and $book['{http://owncloud.org/ns}read-only']); } } @@ -647,7 +571,7 @@ private function addressBookIsReadOnly(string $bookid): bool { } /** - * @return array + * @return array */ private function getAddressBooksReadOnly(): array { $booksReadOnly = []; @@ -660,11 +584,6 @@ private function getAddressBooksReadOnly(): array { } /** - * @param float $lat - * @param float $lng - * @param string $adr - * @param string $uri - * @return void * @throws \OCP\DB\Exception */ private function setAddressCoordinates(float $lat, float $lng, string $adr, string $uri): void { @@ -704,15 +623,13 @@ private function setAddressCoordinates(float $lat, float $lng, string $adr, stri /** - * get contacts with coordinates + * Get contacts with coordinates * - * @NoAdminRequired - * @NoCSRFRequired - * @param string $name - * @return DataDisplayResponse * @throws NotFoundException * @throws \OCP\Files\NotPermittedException */ + #[NoAdminRequired] + #[NoCSRFRequired] public function getContactLetterAvatar(string $name): DataDisplayResponse { $av = $this->avatarManager->getGuestAvatar($name); $avatarContent = $av->getFile(64)->getContent(); @@ -720,20 +637,10 @@ public function getContactLetterAvatar(string $name): DataDisplayResponse { } /** - * removes the address from the vcard - * and delete corresponding entry in the DB - * - * @NoAdminRequired - * @param string $bookid - * @param string $uri - * @param string $uid - * @param string $adr - * @param string $geo - * @param ?int $fileId - * @param ?int $myMapId - * @return DataResponse + * Removes the address from the vcard and delete corresponding entry in the DB. */ - public function deleteContactAddress($bookid, $uri, $uid, $adr, $geo, $fileId = null, $myMapId = null): DataResponse { + #[NoAdminRequired] + public function deleteContactAddress(int $bookid, string $uri, string $uid, string $adr, string $geo, ?int $fileId = null, ?int $myMapId = null): DataResponse { // vcard $card = $this->cdBackend->getContact($bookid, $uri); diff --git a/lib/Controller/FavoritesController.php b/lib/Controller/FavoritesController.php index 8bada8471..0bc32ae72 100644 --- a/lib/Controller/FavoritesController.php +++ b/lib/Controller/FavoritesController.php @@ -21,7 +21,9 @@ use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\DataResponse; +use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\NotFoundException; use OCP\IConfig; @@ -104,17 +106,17 @@ private function getJSONFavoritesFile(\OCP\Files\Folder $folder): \OCP\Files\Nod } /** - * @NoAdminRequired - * @param ?int $myMapId - * @return DataResponse * @throws \OCP\Files\NotPermittedException */ + #[NoAdminRequired] public function getFavorites(?int $myMapId = null): DataResponse { if (is_null($myMapId) || $myMapId === '') { $favorites = $this->favoritesService->getFavoritesFromDB($this->userId); } else { - $folders = $this->userFolder->getById($myMapId); - $folder = array_shift($folders); + $folder = $this->userFolder->getFirstNodeById($myMapId); + if (!$folder instanceof Folder) { + throw new NotFoundException("Folder with id $myMapId does not exist"); + } $file = $this->getJSONFavoritesFile($folder); $favorites = $this->favoritesService->getFavoritesFromJSON($file); } @@ -122,7 +124,6 @@ public function getFavorites(?int $myMapId = null): DataResponse { } /** - * @NoAdminRequired * @param string|null $name * @param float $lat * @param float $lng @@ -135,6 +136,7 @@ public function getFavorites(?int $myMapId = null): DataResponse { * @throws \OCP\Files\InvalidPathException * @throws \OCP\Files\NotPermittedException */ + #[NoAdminRequired] public function addFavorite(?string $name, float $lat, float $lng, ?string $category, ?string $comment, ?string $extensions, ?int $myMapId = null): DataResponse { if (is_numeric($lat) && is_numeric($lng)) { if (is_null($myMapId) || $myMapId === '') { @@ -147,7 +149,7 @@ public function addFavorite(?string $name, float $lat, float $lng, ?string $cate $folders[] = $this->userFolder; } $folder = array_shift($folders); - if (is_null($folder)) { + if (!($folder instanceof Folder)) { return new DataResponse('Map not found', 404); } $file = $this->getJSONFavoritesFile($folder); @@ -162,7 +164,6 @@ public function addFavorite(?string $name, float $lat, float $lng, ?string $cate } /** - * @NoAdminRequired * @param array $favorites * @param int|null $myMapId * @return DataResponse @@ -170,6 +171,7 @@ public function addFavorite(?string $name, float $lat, float $lng, ?string $cate * @throws \OCP\Files\InvalidPathException * @throws \OCP\Files\NotPermittedException */ + #[NoAdminRequired] public function addFavorites(array $favorites, ?int $myMapId = null): DataResponse { if (is_null($myMapId) || $myMapId === '') { $favoritesAfter = []; @@ -188,7 +190,7 @@ public function addFavorites(array $favorites, ?int $myMapId = null): DataRespon $folders[] = $this->userFolder; } $folder = array_shift($folders); - if (is_null($folder)) { + if (!$folder instanceof Folder) { return new DataResponse('Map not found', 404); } $file = $this->getJSONFavoritesFile($folder); @@ -204,7 +206,6 @@ public function addFavorites(array $favorites, ?int $myMapId = null): DataRespon } /** - * @NoAdminRequired * @param int $id * @param string|null $name * @param float $lat @@ -216,6 +217,7 @@ public function addFavorites(array $favorites, ?int $myMapId = null): DataRespon * @return DataResponse * @throws \OCP\Files\NotPermittedException */ + #[NoAdminRequired] public function editFavorite(int $id, ?string $name, float $lat, float $lng, ?string $category, ?string $comment, ?string $extensions, ?int $myMapId = null): DataResponse { if (is_null($myMapId) || $myMapId === '') { $favorite = $this->favoritesService->getFavoriteFromDB($id, $this->userId); @@ -233,8 +235,10 @@ public function editFavorite(int $id, ?string $name, float $lat, float $lng, ?st return new DataResponse($this->l->t('no such favorite'), 400); } } else { - $folders = $this->userFolder->getById($myMapId); - $folder = array_shift($folders); + $folder = $this->userFolder->getFirstNodeById($myMapId); + if (!$folder instanceof Folder) { + return new DataResponse('Map not found', 404); + } $file = $this->getJSONFavoritesFile($folder); $favorite = $this->favoritesService->getFavoriteFromJSON($file, $id, $this->userId); if ($favorite !== null) { @@ -254,7 +258,6 @@ public function editFavorite(int $id, ?string $name, float $lat, float $lng, ?st } /** - * @NoAdminRequired * @param array $categories * @param string $newName * @param int|null $myMapId @@ -262,6 +265,7 @@ public function editFavorite(int $id, ?string $name, float $lat, float $lng, ?st * @throws \OCP\DB\Exception * @throws \OCP\Files\NotPermittedException */ + #[NoAdminRequired] public function renameCategories(array $categories, string $newName, ?int $myMapId = null): DataResponse { if (is_array($categories)) { foreach ($categories as $cat) { @@ -276,8 +280,10 @@ public function renameCategories(array $categories, string $newName, ?int $myMap } catch (DoesNotExistException|MultipleObjectsReturnedException $e) { } } else { - $folders = $this->userFolder->getById($myMapId); - $folder = array_shift($folders); + $folder = $this->userFolder->getFirstNodeById($myMapId); + if (!$folder instanceof Folder) { + return new DataResponse('Map not found', 404); + } $file = $this->getJSONFavoritesFile($folder); $this->favoritesService->renameCategoryInJSON($file, $cat, $newName); } @@ -287,12 +293,12 @@ public function renameCategories(array $categories, string $newName, ?int $myMap } /** - * @NoAdminRequired * @param int $id * @param int|null $myMapId * @return DataResponse * @throws \OCP\Files\NotPermittedException */ + #[NoAdminRequired] public function deleteFavorite(int $id, ?int $myMapId = null): DataResponse { if (is_null($myMapId) || $myMapId === '') { $favorite = $this->favoritesService->getFavoriteFromDB($id, $this->userId); @@ -302,8 +308,10 @@ public function deleteFavorite(int $id, ?int $myMapId = null): DataResponse { } return new DataResponse($this->l->t('no such favorite'), 400); } - $folders = $this->userFolder->getById($myMapId); - $folder = array_shift($folders); + $folder = $this->userFolder->getFirstNodeById($myMapId); + if (!$folder instanceof Folder) { + return new DataResponse('Map not found', 404); + } $file = $this->getJSONFavoritesFile($folder); if ($this->favoritesService->deleteFavoriteFromJSON($file, $id) > 0) { return new DataResponse('DELETED'); @@ -312,18 +320,20 @@ public function deleteFavorite(int $id, ?int $myMapId = null): DataResponse { } /** - * @NoAdminRequired * @param array $ids * @param int|null $myMapId * @return DataResponse * @throws \OCP\Files\NotPermittedException */ + #[NoAdminRequired] public function deleteFavorites(array $ids, ?int $myMapId = null): DataResponse { if (is_null($myMapId) || $myMapId === '') { $this->favoritesService->deleteFavoritesFromDB($ids, $this->userId); } else { - $folders = $this->userFolder->getById($myMapId); - $folder = array_shift($folders); + $folder = $this->userFolder->getFirstNodeById($myMapId); + if (!$folder instanceof Folder) { + return new DataResponse('Map not found', 404); + } $file = $this->getJSONFavoritesFile($folder); $this->favoritesService->deleteFavoritesFromJSON($file, $ids); } @@ -331,14 +341,12 @@ public function deleteFavorites(array $ids, ?int $myMapId = null): DataResponse } /** - * @NoAdminRequired - * @param int|null $myMapId - * @return DataResponse * @throws \OCP\Files\NotPermittedException * @throws \OC\User\NoUserException */ + #[NoAdminRequired] public function getSharedCategories(?int $myMapId = null): DataResponse { - if (is_null($myMapId) || $myMapId === '') { + if (is_null($myMapId)) { $categories = $this->favoriteShareMapper->findAllByOwner($this->userId); } else { $categories = $this->favoriteShareMapper->findAllByMapId($this->userId, $myMapId); @@ -347,11 +355,7 @@ public function getSharedCategories(?int $myMapId = null): DataResponse { return new DataResponse($categories); } - /** - * @NoAdminRequired - * @param string $category - * @return DataResponse - */ + #[NoAdminRequired] public function shareCategory(string $category): DataResponse { if ($this->favoritesService->countFavorites($this->userId, [$category], null, null) === 0) { return new DataResponse($this->l->t('Unknown category'), Http::STATUS_BAD_REQUEST); @@ -366,11 +370,7 @@ public function shareCategory(string $category): DataResponse { return new DataResponse($share); } - /** - * @NoAdminRequired - * @param string $category - * @return DataResponse - */ + #[NoAdminRequired] public function unShareCategory(string $category): DataResponse { if ($this->favoritesService->countFavorites($this->userId, [$category], null, null) === 0) { return new DataResponse($this->l->t('Unknown category'), Http::STATUS_BAD_REQUEST); @@ -384,7 +384,6 @@ public function unShareCategory(string $category): DataResponse { } /** - * @NoAdminRequired * @param string $category * @param int $targetMapId * @param int|null $myMapId @@ -394,6 +393,7 @@ public function unShareCategory(string $category): DataResponse { * @throws \OCP\Files\NotPermittedException * @throws \OC\User\NoUserException */ + #[NoAdminRequired] public function addShareCategoryToMap(string $category, int $targetMapId, ?int $myMapId = null): DataResponse { if (is_null($myMapId) || $myMapId === '') { $share = $this->favoriteShareMapper->findByOwnerAndCategory($this->userId, $category); @@ -422,12 +422,7 @@ public function addShareCategoryToMap(string $category, int $targetMapId, ?int $ return new DataResponse('Done'); } - /** - * @NoAdminRequired - * @param string $category - * @param int $myMapId - * @return DataResponse - */ + #[NoAdminRequired] public function removeShareCategoryFromMap(string $category, int $myMapId): DataResponse { $d = $this->favoriteShareMapper->removeByMapIdAndCategory($this->userId, $myMapId, $category); if (is_null($d)) { @@ -437,7 +432,6 @@ public function removeShareCategoryFromMap(string $category, int $myMapId): Data } /** - * @NoAdminRequired * @param array|null $categoryList * @param int|null $begin * @param int|null $end @@ -446,6 +440,7 @@ public function removeShareCategoryFromMap(string $category, int $myMapId): Data * @throws NotFoundException * @throws \OCP\Files\NotPermittedException */ + #[NoAdminRequired] public function exportFavorites(?array $categoryList = null, ?int $begin = null, ?int $end = null, bool $all = false): DataResponse { // sorry about ugly categoryList management: // when an empty list is passed in http request, we get null here @@ -500,50 +495,35 @@ public function exportFavorites(?array $categoryList = null, ?int $begin = null, } /** - * @NoAdminRequired - * @param string $path - * @return DataResponse * @throws NotFoundException * @throws \OCP\Files\InvalidPathException */ + #[NoAdminRequired] public function importFavorites(string $path): DataResponse { $userFolder = $this->userFolder; - $cleanpath = str_replace(['../', '..\\'], '', $path); - - if ($userFolder->nodeExists($cleanpath)) { - $file = $userFolder->get($cleanpath); - if ($file->getType() === \OCP\Files\FileInfo::TYPE_FILE - and $file->isReadable()) { - $lowerFileName = strtolower($file->getName()); - if ($this->endswith($lowerFileName, '.gpx') or $this->endswith($lowerFileName, '.kml') or $this->endswith($lowerFileName, '.kmz') or $this->endswith($lowerFileName, '.json') or $this->endswith($lowerFileName, '.geojson')) { - $result = $this->favoritesService->importFavorites($this->userId, $file); - return new DataResponse($result); - } else { - // invalid extension - return new DataResponse($this->l->t('Invalid file extension'), 400); - } - } else { - // directory or not readable - return new DataResponse($this->l->t('Impossible to read the file'), 400); - } - } else { - // does not exist + $cleanPath = str_replace(['../', '..\\'], '', $path); + + if (!$userFolder->nodeExists($cleanPath)) { return new DataResponse($this->l->t('File does not exist'), 400); } - } - /** - * @param string $string - * @param string $test - * @return bool - */ - private function endswith(string $string, string $test): bool { - $strlen = strlen($string); - $testlen = strlen($test); - if ($testlen > $strlen) { - return false; + $file = $userFolder->get($cleanPath); + if (!$file instanceof File || !$file->isReadable()) { + // directory or not readable + return new DataResponse($this->l->t('Impossible to read the file'), 400); } - return substr_compare($string, $test, $strlen - $testlen, $testlen) === 0; - } + $lowerFileName = strtolower($file->getName()); + if (str_ends_with($lowerFileName, '.gpx') + || str_ends_with($lowerFileName, '.kml') + || str_ends_with($lowerFileName, '.kmz') + || str_ends_with($lowerFileName, '.json') + || str_ends_with($lowerFileName, '.geojson')) { + $result = $this->favoritesService->importFavorites($this->userId, $file); + return new DataResponse($result); + } else { + // invalid extension + return new DataResponse($this->l->t('Invalid file extension'), 400); + } + } } diff --git a/lib/Controller/PhotosController.php b/lib/Controller/PhotosController.php index dffc0083a..fb1abaefa 100644 --- a/lib/Controller/PhotosController.php +++ b/lib/Controller/PhotosController.php @@ -17,6 +17,8 @@ use OCA\Maps\Service\PhotofilesService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\DataResponse; use OCP\DB\Exception; use OCP\Files\Folder; @@ -27,52 +29,37 @@ use OCP\IRequest; class PhotosController extends Controller { - private $userId; - private $geophotoService; - private $photofilesService; - private $root; - - public function __construct($AppName, + public function __construct( + string $appName, IRequest $request, - GeophotoService $GeophotoService, - PhotofilesService $photofilesService, - IRootFolder $root, - $UserId) { - parent::__construct($AppName, $request); - $this->userId = $UserId; - $this->geophotoService = $GeophotoService; - $this->photofilesService = $photofilesService; - $this->root = $root; + private GeophotoService $geophotoService, + private PhotofilesService $photofilesService, + private IRootFolder $root, + private string $userId, + ) { + parent::__construct($appName, $request); } /** - * @NoAdminRequired - * @NoCSRFRequired - * @param null $myMapId - * @param null $respectNoMediaAndNoimage - * @param null $hideImagesOnCustomMaps - * @param null $hideImagesInMapsFolder - * @return DataResponse * @throws Exception * @throws NoUserException * @throws NotFoundException * @throws NotPermittedException */ - public function getPhotos($myMapId = null, $respectNoMediaAndNoimage = null, $hideImagesOnCustomMaps = null, $hideImagesInMapsFolder = null): DataResponse { + #[NoAdminRequired] + #[NoCSRFRequired] + public function getPhotos(?int $myMapId = null, bool $respectNoMediaAndNoimage = true, bool $hideImagesOnCustomMaps = false, bool $hideImagesInMapsFolder = true): DataResponse { $userFolder = $this->root->getUserFolder($this->userId); - if (is_null($myMapId) || $myMapId === '') { - $result = $this->geophotoService->getAll($this->userId, $userFolder, $respectNoMediaAndNoimage ?? true, $hideImagesOnCustomMaps ?? false, $hideImagesInMapsFolder ?? true); + if (is_null($myMapId)) { + $result = $this->geophotoService->getAll($this->userId, $userFolder, $respectNoMediaAndNoimage, $hideImagesOnCustomMaps, $hideImagesInMapsFolder); } else { - $folders = $userFolder->getById($myMapId); - $folder = array_shift($folders); - $result = $this->geophotoService->getAll($this->userId, $folder, $respectNoMediaAndNoimage ?? true, $hideImagesOnCustomMaps ?? false, $hideImagesInMapsFolder ?? false); + $folder = $userFolder->getFirstNodeById($myMapId); + $result = $this->geophotoService->getAll($this->userId, $folder, $respectNoMediaAndNoimage, $hideImagesOnCustomMaps, $hideImagesInMapsFolder); } return new DataResponse($result); } /** - * @NoAdminRequired - * @NoCSRFRequired * @param int|null $myMapId * @param string|null $timezone * @param int $limit @@ -86,13 +73,17 @@ public function getPhotos($myMapId = null, $respectNoMediaAndNoimage = null, $hi * @throws NotFoundException * @throws NotPermittedException */ + #[NoAdminRequired] + #[NoCSRFRequired] public function getNonLocalizedPhotos(?int $myMapId = null, ?string $timezone = null, int $limit = 250, int $offset = 0, $respectNoMediaAndNoimage = null, $hideImagesOnCustomMaps = null, $hideImagesInMapsFolder = null): DataResponse { $userFolder = $this->root->getUserFolder($this->userId); - if (is_null($myMapId) || $myMapId === '') { + if (is_null($myMapId)) { $result = $this->geophotoService->getNonLocalized($this->userId, $userFolder, $respectNoMediaAndNoimage ?? true, $hideImagesOnCustomMaps ?? false, $hideImagesInMapsFolder ?? true, $timezone, $limit, $offset); } else { - $folders = $userFolder->getById($myMapId); - $folder = array_shift($folders); + $folder = $userFolder->getFirstNodeById($myMapId); + if ($folder instanceof Folder) { + throw new NotFoundException('Could find map with mapid: ' . $myMapId); + } $result = $this->geophotoService->getNonLocalized($this->userId, $folder, $respectNoMediaAndNoimage ?? true, $hideImagesOnCustomMaps ?? false, $hideImagesInMapsFolder ?? false, $timezone, $limit, $offset); } return new DataResponse($result); @@ -100,12 +91,9 @@ public function getNonLocalizedPhotos(?int $myMapId = null, ?string $timezone = /** - * @NoAdminRequired * @param $paths * @param $lats * @param $lngs - * @param bool $directory - * @param null $myMapId * @param bool $relative * @return DataResponse * @throws NoUserException @@ -113,10 +101,11 @@ public function getNonLocalizedPhotos(?int $myMapId = null, ?string $timezone = * @throws NotPermittedException * @throws InvalidPathException */ - public function placePhotos($paths, $lats, $lngs, bool $directory = false, $myMapId = null, bool $relative = false): DataResponse { + #[NoAdminRequired] + public function placePhotos($paths, $lats, $lngs, bool $directory = false, ?int $myMapId = null, bool $relative = false): DataResponse { $userFolder = $this->root->getUserFolder($this->userId); - if (!is_null($myMapId) and $myMapId !== '') { - if ($directory === 'true') { + if (!is_null($myMapId)) { + if ($directory) { // forbid folder placement in my-maps throw new NotPermittedException(); } @@ -137,7 +126,7 @@ public function placePhotos($paths, $lats, $lngs, bool $directory = false, $myMa foreach ($paths as $key => $path) { $photoFile = $userFolder->get($path); // is the photo in this map's folder? - if (!$folder->getById($photoFile->getId())) { + if ($folder->getFirstNodeById($photoFile->getId()) !== null) { $copiedFile = $photoFile->copy($folder->getPath() . '/' . $photoFile->getName()); $paths[$key] = $userFolder->getRelativePath($copiedFile->getPath()); } @@ -149,22 +138,20 @@ public function placePhotos($paths, $lats, $lngs, bool $directory = false, $myMa } /** - * @NoAdminRequired * @param $paths - * @return DataResponse */ - public function resetPhotosCoords($paths, $myMapId = null): DataResponse { + #[NoAdminRequired] + public function resetPhotosCoords($paths, ?int $myMapId = null): DataResponse { $userFolder = $this->root->getUserFolder($this->userId); $result = []; if (sizeof($paths) > 0) { $result = $this->photofilesService->resetPhotosFilesCoords($this->userId, $paths); } - if (!is_null($myMapId) and $myMapId !== '') { + if (!is_null($myMapId)) { foreach ($paths as $key => $path) { - $folders = $userFolder->getById($myMapId); - $folder = array_shift($folders); + $folder = $userFolder->getFirstNodeById($myMapId); $photoFile = $userFolder->get($path); - if ($folder->isSubNode($photoFile)) { + if ($folder instanceof Folder && $folder->isSubNode($photoFile)) { $photoFile->delete(); unset($paths[$key]); } @@ -173,10 +160,7 @@ public function resetPhotosCoords($paths, $myMapId = null): DataResponse { return new DataResponse($result); } - /** - * @NoAdminRequired - * @return DataResponse - */ + #[NoAdminRequired] public function clearCache(): DataResponse { $result = $this->geophotoService->clearCache(); if ($result) { @@ -186,10 +170,7 @@ public function clearCache(): DataResponse { } } - /** - * @NoAdminRequired - * @return DataResponse - */ + #[NoAdminRequired] public function getBackgroundJobStatus(): DataResponse { return new DataResponse($this->photofilesService->getBackgroundJobStatus($this->userId)); } diff --git a/lib/Controller/PublicPageController.php b/lib/Controller/PublicPageController.php index 9026d6fa1..a1d75e532 100644 --- a/lib/Controller/PublicPageController.php +++ b/lib/Controller/PublicPageController.php @@ -45,11 +45,6 @@ public function __construct( protected IUserManager $userManager, ) { parent::__construct($appName, $request, $session, $urlGenerator); - $this->eventDispatcher = $eventDispatcher; - $this->config = $config; - $this->initialStateService = $initialStateService; - $this->shareManager = $shareManager; - $this->userManager = $userManager; } public function isValidToken(): bool { @@ -76,10 +71,8 @@ protected function isPasswordProtected(): bool { /** * Validate the permissions of the share - * - * @return bool */ - private function validateShare(\OCP\Share\IShare $share) { + private function validateShare(\OCP\Share\IShare $share): bool { // If the owner is disabled no access to the link is granted $owner = $this->userManager->get($share->getShareOwner()); if ($owner === null || !$owner->isEnabled()) { diff --git a/lib/Controller/PublicTracksController.php b/lib/Controller/PublicTracksController.php index cc7834113..a8ae719d8 100644 --- a/lib/Controller/PublicTracksController.php +++ b/lib/Controller/PublicTracksController.php @@ -13,9 +13,14 @@ namespace OCA\Maps\Controller; use OCA\Maps\Service\TracksService; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\DataResponse; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\File; +use OCP\Files\Folder; use OCP\Files\IRootFolder; +use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OCP\IConfig; @@ -23,7 +28,6 @@ use OCP\IInitialStateService; use OCP\IL10N; use OCP\IRequest; -use OCP\IServerContainer; use OCP\ISession; use OCP\IURLGenerator; use OCP\IUserManager; @@ -31,18 +35,10 @@ use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IManager as ShareManager; +use OCP\Share\IShare; use function OCA\Maps\Helper\remove_utf8_bom; class PublicTracksController extends PublicPageController { - - protected IConfig $config; - protected ShareManager $shareManager; - protected IUserManager $userManager; - protected IL10N $l; - protected TracksService $tracksService; - protected $appName; - protected IRootFolder $root; - public function __construct( string $appName, IRequest $request, @@ -53,24 +49,18 @@ public function __construct( ShareManager $shareManager, IUserManager $userManager, ISession $session, - IServerContainer $serverContainer, protected IGroupManager $groupManager, - IL10N $l, - TracksService $tracksService, - IRootFolder $root, + protected IL10N $l, + protected TracksService $tracksService, + protected IRootFolder $root, ) { parent::__construct($appName, $request, $session, $urlGenerator, $eventDispatcher, $config, $initialStateService, $shareManager, $userManager); - $this->tracksService = $tracksService; - $this->l = $l; - $this->root = $root; } /** * Validate the permissions of the share - * - * @return bool */ - private function validateShare(\OCP\Share\IShare $share) { + private function validateShare(\OCP\Share\IShare $share): bool { // If the owner is disabled no access to the link is granted $owner = $this->userManager->get($share->getShareOwner()); if ($owner === null || !$owner->isEnabled()) { @@ -87,10 +77,9 @@ private function validateShare(\OCP\Share\IShare $share) { } /** - * @return \OCP\Share\IShare * @throws NotFoundException */ - private function getShare() { + private function getShare(): IShare { // Check whether share exists try { $share = $this->shareManager->getShareByToken($this->getToken()); @@ -106,10 +95,9 @@ private function getShare() { } /** - * @return \OCP\Files\File|\OCP\Files\Folder * @throws NotFoundException */ - private function getShareNode() { + private function getShareNode(): Node { \OC_User::setIncognitoMode(true); $share = $this->getShare(); @@ -118,152 +106,140 @@ private function getShareNode() { } /** - * @PublicPage - * @return DataResponse * @throws NotFoundException * @throws NotPermittedException * @throws \OC\User\NoUserException */ + #[PublicPage] public function getTracks(): DataResponse { $share = $this->getShare(); $hideDownload = (bool)$share->getHideDownload(); $permissions = $share->getPermissions(); $folder = $this->getShareNode(); $isReadable = (bool)($permissions & (1 << 0)); - if ($isReadable) { - $owner = $share->getShareOwner(); - $pre_path = $this->root->getUserFolder($owner)->getPath(); - $tracks = $this->tracksService->getTracksFromDB($owner, $folder, true, false, false); - $new_tracks = array_map(function ($track) use ($folder, $permissions, $pre_path, $hideDownload) { - $track['isCreatable'] = ($permissions & (1 << 2)) && $track['isCreatable']; - $track['isUpdateable'] = ($permissions & (1 << 1)) && $track['isUpdateable']; - $track['isDeletable'] = ($permissions & (1 << 3)) && $track['isDeletable']; - $track['path'] = $folder->getRelativePath($pre_path . $track['path']); - $track['filename'] = $track['path']; - $track['hideDownload'] = $hideDownload; - return $track; - }, $tracks); - } else { + if (!$isReadable || !($folder instanceof Folder)) { throw new NotPermittedException(); } - return new DataResponse($new_tracks); + + $owner = $share->getShareOwner(); + $pre_path = $this->root->getUserFolder($owner)->getPath(); + $tracks = $this->tracksService->getTracksFromDB($owner, $folder, true, false, false); + $newTracks = array_map(function ($track) use ($folder, $permissions, $pre_path, $hideDownload): array { + $track['isCreatable'] = ($permissions & (1 << 2)) && $track['isCreatable']; + $track['isUpdateable'] = ($permissions & (1 << 1)) && $track['isUpdateable']; + $track['isDeletable'] = ($permissions & (1 << 3)) && $track['isDeletable']; + $track['path'] = $folder->getRelativePath($pre_path . $track['path']); + $track['filename'] = $track['path']; + $track['hideDownload'] = $hideDownload; + return $track; + }, $tracks); + return new DataResponse($newTracks); } /** - * @PublicPage - * @param $id - * @return DataResponse * @throws NotFoundException * @throws NotPermittedException * @throws \OCP\Files\InvalidPathException */ - public function getTrackContentByFileId($id) { + #[PublicPage] + public function getTrackContentByFileId(int $id): DataResponse { $share = $this->getShare(); $permissions = $share->getPermissions(); $folder = $this->getShareNode(); $isReadable = (bool)($permissions & (1 << 0)); - if (!$isReadable) { + if (!$isReadable || !($folder instanceof Folder)) { throw new NotPermittedException(); } $owner = $share->getShareOwner(); $track = $this->tracksService->getTrackByFileIDFromDB($id, $owner); - $res = is_null($track) ? null : $folder->getById($track['file_id']); - if (is_array($res) and count($res) > 0) { - $trackFile = array_shift($res); - if ($trackFile->getType() === \OCP\Files\FileInfo::TYPE_FILE) { - $trackContent = remove_utf8_bom($trackFile->getContent()); - // compute metadata if necessary - // first time we get it OR the file changed - if (!$track['metadata'] || $track['etag'] !== $trackFile->getEtag()) { - $metadata = $this->tracksService->generateTrackMetadata($trackFile); - $this->tracksService->editTrackInDB($track['id'], null, $metadata, $trackFile->getEtag()); - } else { - $metadata = $track['metadata']; - } - return new DataResponse([ - 'metadata' => $metadata, - 'content' => $trackContent - ]); - } else { - return new DataResponse($this->l->t('Bad file type'), 400); - } - } else { + $trackFile = is_null($track) ? null : $folder->getFirstNodeById($track['file_id']); + if (!($trackFile instanceof File)) { return new DataResponse($this->l->t('File not found'), 400); } + + if ($trackFile->getType() !== \OCP\Files\FileInfo::TYPE_FILE) { + return new DataResponse($this->l->t('Bad file type'), 400); + } + + $trackContent = remove_utf8_bom($trackFile->getContent()); + // compute metadata if necessary + // first time we get it OR the file changed + if (!$track['metadata'] || $track['etag'] !== $trackFile->getEtag()) { + $metadata = $this->tracksService->generateTrackMetadata($trackFile); + $this->tracksService->editTrackInDB($track['id'], null, $metadata, $trackFile->getEtag()); + } else { + $metadata = $track['metadata']; + } + return new DataResponse([ + 'metadata' => $metadata, + 'content' => $trackContent + ]); } /** - * @PublicPage - * @param $id * @return DataResponse * @throws NotFoundException * @throws \OCP\Files\InvalidPathException */ - public function getTrackFileContent($id): DataResponse { + #[PublicPage] + public function getTrackFileContent(int $id): DataResponse { $track = $this->tracksService->getTrackFromDB($id); - $res = is_null($track) ? null : $this->getShareNode()->getById($track['file_id']); - if (is_array($res) and count($res) > 0) { - $trackFile = array_shift($res); - if ($trackFile->getType() === \OCP\Files\FileInfo::TYPE_FILE) { - $trackContent = remove_utf8_bom($trackFile->getContent()); - // compute metadata if necessary - // first time we get it OR the file changed - if (!$track['metadata'] || $track['etag'] !== $trackFile->getEtag()) { - $metadata = $this->tracksService->generateTrackMetadata($trackFile); - $this->tracksService->editTrackInDB($track['id'], null, $metadata, $trackFile->getEtag()); - } else { - $metadata = $track['metadata']; - } - return new DataResponse([ - 'metadata' => $metadata, - 'content' => $trackContent - ]); - } else { - return new DataResponse($this->l->t('Bad file type'), 400); - } - } else { + $shareNode = $this->getShareNode(); + if (!($shareNode instanceof Folder)) { return new DataResponse($this->l->t('File not found'), 400); } + + $trackFile = is_null($track) ? null : $shareNode->getFirstNodeById($track['file_id']); + if (!($trackFile instanceof File)) { + return new DataResponse($this->l->t('File not found'), 400); + } + + if ($trackFile->getType() !== \OCP\Files\FileInfo::TYPE_FILE) { + return new DataResponse($this->l->t('Bad file type'), 400); + } + + $trackContent = remove_utf8_bom($trackFile->getContent()); + // compute metadata if necessary + // first time we get it OR the file changed + if (!$track['metadata'] || $track['etag'] !== $trackFile->getEtag()) { + $metadata = $this->tracksService->generateTrackMetadata($trackFile); + $this->tracksService->editTrackInDB($track['id'], null, $metadata, $trackFile->getEtag()); + } else { + $metadata = $track['metadata']; + } + return new DataResponse([ + 'metadata' => $metadata, + 'content' => $trackContent + ]); } /** - * @PublicPage - * @param $id - * @param $color - * @param $metadata - * @param $etag - * @return DataResponse * @throws NotFoundException * @throws NotPermittedException */ - public function editTrack($id, $color, $metadata, $etag): DataResponse { + #[PublicPage] + public function editTrack(int $id, string $color, string $metadata, string $etag): DataResponse { $share = $this->getShare(); $permissions = $share->getPermissions(); - $folder = $this->getShareNode(); $isUpdateable = (bool)($permissions & (1 << 1)); - if ($isUpdateable) { - $owner = $share->getShareOwner(); - $track = $this->tracksService->getTrackFromDB($id, $owner); - if ($track !== null) { - $this->tracksService->editTrackInDB($id, $color, $metadata, $etag); - return new DataResponse('EDITED'); - } else { - return new DataResponse($this->l->t('No such track'), 400); - } - } else { + if (!$isUpdateable) { throw new NotPermittedException(); } + + $owner = $share->getShareOwner(); + $track = $this->tracksService->getTrackFromDB($id, $owner); + if ($track !== null) { + $this->tracksService->editTrackInDB($id, $color, $metadata, $etag); + return new DataResponse('EDITED'); + } else { + return new DataResponse($this->l->t('No such track'), 400); + } } - /** - * @NoAdminRequired - * @param $id - * @return DataResponse - */ - public function deleteTrack($id): DataResponse { + #[NoAdminRequired] + public function deleteTrack(int $id): DataResponse { $share = $this->getShare(); $permissions = $share->getPermissions(); - $folder = $this->getShareNode(); $isUpdateable = (bool)($permissions & (1 << 1)); //It's allowed to delete a track from the share, if the share is updateable if ($isUpdateable) { @@ -279,5 +255,4 @@ public function deleteTrack($id): DataResponse { throw new NotPermittedException(); } } - } diff --git a/lib/Controller/UtilsController.php b/lib/Controller/UtilsController.php index d8b7ecc68..e7ce86c0d 100644 --- a/lib/Controller/UtilsController.php +++ b/lib/Controller/UtilsController.php @@ -13,13 +13,16 @@ namespace OCA\Maps\Controller; -use OCP\App\IAppManager; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\ContentSecurityPolicy; use OCP\AppFramework\Http\DataResponse; +use OCP\Files\File; +use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; @@ -28,33 +31,24 @@ use OCP\Lock\LockedException; class UtilsController extends Controller { - - - private $userId; - private $config; - private $root; - - public function __construct($AppName, + public function __construct( + string $appName, IRequest $request, - IConfig $config, - IAppManager $appManager, - IRootFolder $root, - $UserId) { - parent::__construct($AppName, $request); - $this->root = $root; - $this->userId = $UserId; - // IConfig object - $this->config = $config; + private IConfig $config, + private IRootFolder $root, + private string $userId, + ) { + parent::__construct($appName, $request); } /** * Save options values to the DB for current user * - * @NoAdminRequired * @param $options * @return DataResponse * @throws \OCP\PreConditionNotMetException */ + #[NoAdminRequired] public function saveOptionValue($options, $myMapId = null): DataResponse { if (is_null($myMapId) || $myMapId === '') { foreach ($options as $key => $value) { @@ -62,9 +56,12 @@ public function saveOptionValue($options, $myMapId = null): DataResponse { } } else { $userFolder = $this->root->getUserFolder($this->userId); - $folders = $userFolder->getById($myMapId); - $folder = array_shift($folders); + $folder = $userFolder->getFirstNodeById($myMapId); + if (!$folder instanceof Folder) { + throw new NotFoundException('Could find map with mapid: ' . $myMapId); + } try { + /** @var File $file */ $file = $folder->get('.index.maps'); } catch (NotFoundException $e) { $file = $folder->newFile('.index.maps', $content = '{}'); @@ -83,11 +80,9 @@ public function saveOptionValue($options, $myMapId = null): DataResponse { } /** - * get options values from the config for current user - * - * @NoAdminRequired - * @return DataResponse + * Get options values from the config for current user */ + #[NoAdminRequired] public function getOptionsValues($myMapId = null): DataResponse { $ov = []; @@ -105,9 +100,12 @@ public function getOptionsValues($myMapId = null): DataResponse { $ov['isShareable'] = true; } else { $userFolder = $this->root->getUserFolder($this->userId); - $folders = $userFolder->getById($myMapId); - $folder = array_shift($folders); + $folder = $userFolder->getFirstNodeById($myMapId); + if (!$folder instanceof Folder) { + throw new NotFoundException('Could find map with mapid: ' . $myMapId); + } try { + /** @var File $file */ $file = $folder->get('.index.maps'); } catch (NotFoundException $e) { $file = $folder->newFile('.index.maps', $content = '{}'); @@ -178,12 +176,10 @@ public function setRoutingSettings($values): DataResponse { } /** - * get content of mapbox traffic style - * @NoAdminRequired - * @NoCSRFRequired - * - * @return DataResponse + * Get content of mapbox traffic style */ + #[NoAdminRequired] + #[NoCSRFRequired] public function getTrafficStyle(): DataResponse { $style = [ 'version' => 8, diff --git a/lib/Hooks/FileHooks.php b/lib/Hooks/FileHooks.php index 90d2557fe..edeab0479 100644 --- a/lib/Hooks/FileHooks.php +++ b/lib/Hooks/FileHooks.php @@ -15,7 +15,9 @@ use OC\Files\Filesystem; use OCA\Maps\Service\PhotofilesService; use OCA\Maps\Service\TracksService; +use OCP\Files\File; use OCP\Files\FileInfo; +use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Lock\ILockingProvider; use OCP\Share\IShare; @@ -27,22 +29,15 @@ */ class FileHooks { - private $photofilesService; - private $tracksService; - - private $root; - - private ILockingProvider $lockingProvider; - - public function __construct(IRootFolder $root, PhotofilesService $photofilesService, TracksService $tracksService, - $appName, ILockingProvider $lockingProvider) { - $this->photofilesService = $photofilesService; - $this->tracksService = $tracksService; - $this->root = $root; - $this->lockingProvider = $lockingProvider; + public function __construct( + private IRootFolder $root, + private PhotofilesService $photofilesService, + private TracksService $tracksService, + private ILockingProvider $lockingProvider, + ) { } - public function register() { + public function register(): void { $fileWriteCallback = function (\OCP\Files\Node $node) { //logger('maps')->debug("Hook postWrite"); if ($node->getType() === FileInfo::TYPE_FILE && $this->isUserNode($node) && $node->getSize()) { @@ -112,32 +107,30 @@ public function register() { Util::connectHook(\OCP\Share::class, 'pre_unshare', $this, 'preUnShare'); } - public function postShare($params) { + public function postShare(array $params): void { //logger('maps')->debug("Hook postShare"); if ($params['itemType'] === 'file') { //$targetFilePath = $params['itemTarget']; //$sourceUserId = $params['uidOwner']; $fileId = $params['fileSource']; // or itemSource - $files = $this->root->getById($fileId); - if (empty($files)) { + $file = $this->root->getFirstNodeById($fileId); + if ($file instanceof File) { return; } - $file = array_shift($files); - $this->photofilesService->addByFile($file, ); + $this->photofilesService->addByFile($file); $this->tracksService->safeAddByFile($file); } elseif ($params['itemType'] === 'folder') { $dirId = $params['fileSource']; // or itemSource - $folders = $this->root->getById($dirId); - if (empty($folders)) { + $folder = $this->root->getFirstNodeById($dirId); + if ($folder instanceof Folder) { return; } - $folder = array_shift($folders); $this->photofilesService->addByFolder($folder); $this->tracksService->safeAddByFolder($folder); } } - public function postUnShare($params) { + public function postUnShare(array $params): void { //logger('maps')->debug("Hook postUnShare"); if ($params['shareType'] === IShare::TYPE_USER) { if ($params['itemType'] === 'file') { @@ -149,7 +142,7 @@ public function postUnShare($params) { } } - public function preUnShare($params) { + public function preUnShare(array $params): void { //logger('maps')->debug("Hook preUnShare"); if ($params['shareType'] === IShare::TYPE_USER) { if ($params['itemType'] === 'folder') { diff --git a/lib/Service/GeophotoService.php b/lib/Service/GeophotoService.php index c5e8f724f..ac80a2524 100644 --- a/lib/Service/GeophotoService.php +++ b/lib/Service/GeophotoService.php @@ -25,56 +25,30 @@ use OCP\Files\NotPermittedException; use OCP\Files\Search\ISearchBinaryOperator; use OCP\Files\Search\ISearchComparison; +use OCP\ICache; use OCP\ICacheFactory; -use OCP\IL10N; use OCP\IPreview; -use Psr\Log\LoggerInterface; use RuntimeException; class GeophotoService { - - private $l10n; - private $root; - private $photoMapper; - private $preview; - private $tracksService; - private $timeorderedPointSets; - private $devicesService; - private $cacheFactory; - private $userId; - private \OCP\ICache $photosCache; - private \OCP\ICache $timeOrderedPointSetsCache; - private \OCP\ICache $backgroundJobCache; + private ICache $photosCache; + private ICache $timeOrderedPointSetsCache; + private ICache $backgroundJobCache; + private $timeorderedPointSets = null; public function __construct( - private LoggerInterface $logger, - IRootFolder $root, - IL10N $l10n, - GeophotoMapper $photoMapper, - IPreview $preview, - TracksService $tracksService, - DevicesService $devicesService, - ICacheFactory $cacheFactory, - $userId, + private IRootFolder $root, + private GeophotoMapper $photoMapper, + private IPreview $preview, + private TracksService $tracksService, + private DevicesService $devicesService, + private ICacheFactory $cacheFactory, ) { - $this->root = $root; - $this->l10n = $l10n; - $this->photoMapper = $photoMapper; - $this->preview = $preview; - $this->tracksService = $tracksService; - $this->timeorderedPointSets = null; - $this->userId = $userId; - $this->devicesService = $devicesService; - $this->cacheFactory = $cacheFactory; $this->photosCache = $this->cacheFactory->createDistributed('maps:photos'); $this->timeOrderedPointSetsCache = $this->cacheFactory->createDistributed('maps:time-ordered-point-sets'); $this->backgroundJobCache = $this->cacheFactory->createDistributed('maps:background-jobs'); } - /** - * @param string $userId - * @return bool - */ public function clearCache(string $userId = ''): bool { try { $this->photosCache->clear($userId); @@ -83,24 +57,18 @@ public function clearCache(string $userId = ''): bool { $this->backgroundJobCache->clear('recentlyUpdated:' . $userId); return true; - } catch (\Exception $e) { + } catch (\Exception) { return false; } } /** - * @param string $userId - * @param ?Folder $folder =null - * @param bool $respectNomediaAndNoimage =true - * @param bool $hideImagesOnCustomMaps =true - * @param bool $hideImagesInMapsFolder - * @return array * @throws Exception * @throws NoUserException * @throws NotFoundException * @throws NotPermittedException */ - public function getAll(string $userId, $folder = null, bool $respectNomediaAndNoimage = true, bool $hideImagesOnCustomMaps = false, bool $hideImagesInMapsFolder = true): array { + public function getAll(string $userId, ?Folder $folder = null, bool $respectNomediaAndNoimage = true, bool $hideImagesOnCustomMaps = false, bool $hideImagesInMapsFolder = true): array { $userFolder = $this->getFolderForUser($userId); if (is_null($folder)) { $folder = $userFolder; @@ -120,12 +88,7 @@ public function getAll(string $userId, $folder = null, bool $respectNomediaAndNo // this path is relative to owner's storage //$path = $cacheEntry->getPath(); //but we want it relative to current user's storage - $files = $folder->getById($photoEntity->getFileId()); - if (empty($files)) { - continue; - } - $file = array_shift($files); - + $file = $folder->getFirstNodeById($photoEntity->getFileId()); if ($file === null) { continue; } @@ -170,11 +133,6 @@ public function getAll(string $userId, $folder = null, bool $respectNomediaAndNo } /** - * @param string $userId - * @param ?Folder $folder =null - * @param bool $respectNomediaAndNoimage - * @param bool $hideImagesOnCustomMaps - * @param bool $hideImagesInMapsFolder * @param string|null $timezone locale time zone used by images * @param int $limit * @param int $offset @@ -184,7 +142,7 @@ public function getAll(string $userId, $folder = null, bool $respectNomediaAndNo * @throws NotFoundException * @throws NotPermittedException */ - public function getNonLocalized(string $userId, $folder = null, bool $respectNomediaAndNoimage = true, bool $hideImagesOnCustomMaps = false, bool $hideImagesInMapsFolder = true, ?string $timezone = null, int $limit = 250, int $offset = 0): array { + public function getNonLocalized(string $userId, ?Folder $folder = null, bool $respectNomediaAndNoimage = true, bool $hideImagesOnCustomMaps = false, bool $hideImagesInMapsFolder = true, ?string $timezone = null, int $limit = 250, int $offset = 0): array { $userFolder = $this->getFolderForUser($userId); if (is_null($folder)) { $folder = $userFolder; @@ -208,11 +166,7 @@ public function getNonLocalized(string $userId, $folder = null, bool $respectNom // this path is relative to owner's storage //$path = $cacheEntry->getPath(); // but we want it relative to current user's storage - $files = $folder->getById($photoEntity->getFileId()); - if (empty($files)) { - continue; - } - $file = array_shift($files); + $file = $folder->getFirstNodeById($photoEntity->getFileId()); if ($file === null) { continue; } @@ -267,14 +221,11 @@ public function getNonLocalized(string $userId, $folder = null, bool $respectNom } /** - * @param $userId - * @param $folder - * @return array * @throws \OCP\Files\NotFoundException * @throws \OCP\Files\NotPermittedException * @throws \OC\User\NoUserException */ - private function getIgnoredPaths($userId, $folder = null, $hideImagesOnCustomMaps = true) { + private function getIgnoredPaths(string $userId, ?Folder $folder = null, bool $hideImagesOnCustomMaps = true): array { $ignoredPaths = []; $userFolder = $this->getFolderForUser($userId); if (is_null($folder)) { @@ -334,13 +285,10 @@ private function loadTimeorderedPointSets(string $userId, $folder = null, bool $ if (is_null($this->timeorderedPointSets)) { $userFolder = $this->getFolderForUser($userId); foreach ($this->tracksService->getTracksFromDB($userId, $folder, $respectNomediaAndNoimage, $hideTracksOnCustomMaps, $hideTracksInMapsFolder) as $gpxfile) { - $res = $userFolder->getById($gpxfile['file_id']); - if (is_array($res) and count($res) > 0) { - $file = array_shift($res); - if ($file instanceof File) { - foreach ($this->getTracksFromGPX($file->getContent()) as $i => $track) { - $this->timeorderedPointSets['track:' . $gpxfile['id'] . ':' . $i] = $this->getTimeorderdPointsFromTrack($track); - } + $file = $userFolder->getFirstNodeById($gpxfile['file_id']); + if ($file instanceof File) { + foreach ($this->getTracksFromGPX($file->getContent()) as $i => $track) { + $this->timeorderedPointSets['track:' . $gpxfile['id'] . ':' . $i] = $this->getTimeorderdPointsFromTrack($track); } } } @@ -454,15 +402,11 @@ private function getPreviewEnabledMimetypes(): array { return $enabledMimeTypes; } - private function normalizePath($path) { + private function normalizePath(string $path): string { return str_replace('files', '', $path); } - /** - * @param string $userId the user id - * @return Folder - */ - private function getFolderForUser($userId) { + private function getFolderForUser(string $userId): Folder { return $this->root->getUserFolder($userId); } diff --git a/lib/Service/PhotofilesService.php b/lib/Service/PhotofilesService.php index a0b979db8..1f30ed6b5 100644 --- a/lib/Service/PhotofilesService.php +++ b/lib/Service/PhotofilesService.php @@ -114,24 +114,16 @@ public function addByFile(Node $file) { } } - public function addByFileIdUserId($fileId, $userId) { + public function addByFileIdUserId(int $fileId, string $userId): void { $userFolder = $this->root->getUserFolder($userId); - $files = $userFolder->getById($fileId); - if (empty($files)) { - return; - } - $file = array_shift($files); + $file = $userFolder->getFirstNodeById($fileId); if ($file !== null and $this->isPhoto($file)) { $this->addPhoto($file, $userId); } } - public function addByFolderIdUserId($folderId, $userId) { - $folders = $this->root->getById($folderId); - if (empty($folders)) { - return; - } - $folder = array_shift($folders); + public function addByFolderIdUserId(int $folderId, string $userId): void { + $folder = $this->root->getFirstNodeById($folderId); if ($folder !== null) { $photos = $this->gatherPhotoFiles($folder, true); foreach ($photos as $photo) { @@ -169,23 +161,23 @@ public function updateByFileNow(Node $file) { } } - public function deleteByFile(Node $file) { + public function deleteByFile(Node $file): void { $this->photoMapper->deleteByFileId($file->getId()); } // delete photo only if it's not accessible to user anymore // it might have been shared multiple times by different users - public function deleteByFileIdUserId($fileId, $userId) { + public function deleteByFileIdUserId(int $fileId, string $userId): void { $userFolder = $this->root->getUserFolder($userId); - $files = $userFolder->getById($fileId); - if (!is_array($files) or count($files) === 0) { + $file = $userFolder->getFirstNodeById($fileId); + if ($file !== null) { $this->photoMapper->deleteByFileIdUserId($fileId, $userId); $this->photosCache->clear($userId); } } - public function deleteByFolder(Node $folder) { + public function deleteByFolder(Node $folder): void { $photos = $this->gatherPhotoFiles($folder, true); foreach ($photos as $photo) { $this->photoMapper->deleteByFileId($photo->getId()); @@ -196,7 +188,7 @@ public function deleteByFolder(Node $folder) { public function deleteByFolderIdUserId($folderId, $userId) { $userFolder = $this->root->getUserFolder($userId); $folders = $userFolder->getById($folderId); - if (is_array($folders) and count($folders) === 1) { + if (is_array($folders) && count($folders) === 1) { $folder = array_shift($folders); $photos = $this->gatherPhotoFiles($folder, true); foreach ($photos as $photo) { @@ -241,7 +233,7 @@ public function getBackgroundJobStatus($userId): array { ]; } - public function setPhotosFilesCoords($userId, $paths, $lats, $lngs, $directory) { + public function setPhotosFilesCoords(string $userId, $paths, $lats, $lngs, $directory) { if ($directory) { return $this->setDirectoriesCoords($userId, $paths, $lats, $lngs); } else { @@ -249,7 +241,7 @@ public function setPhotosFilesCoords($userId, $paths, $lats, $lngs, $directory) } } - private function setDirectoriesCoords($userId, $paths, $lats, $lngs) { + private function setDirectoriesCoords(string $userId, $paths, $lats, $lngs): array { $lat = $lats[0] ?? 0; $lng = $lngs[0] ?? 0; $userFolder = $this->root->getUserFolder($userId); @@ -337,7 +329,7 @@ public function resetPhotosFilesCoords($userId, $paths) { } // avoid adding photo if it already exists in the DB - private function addPhoto($photo, $userId) { + private function addPhoto($photo, string $userId): void { $this->jobList->add(AddPhotoJob::class, ['photoId' => $photo->getId(), 'userId' => $userId]); } diff --git a/lib/Service/TracksService.php b/lib/Service/TracksService.php index 7fd698833..d25581ccf 100644 --- a/lib/Service/TracksService.php +++ b/lib/Service/TracksService.php @@ -16,6 +16,7 @@ use OC\Files\Search\SearchComparison; use OC\Files\Search\SearchQuery; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Files\File; use OCP\Files\FileInfo; use OCP\Files\Folder; use OCP\Files\IRootFolder; @@ -81,27 +82,21 @@ public function safeAddByFile(Node $file) { public function safeAddByFileIdUserId($fileId, $userId) { $userFolder = $this->root->getUserFolder($userId); - $files = $userFolder->getById($fileId); - if (empty($files)) { + $file = $userFolder->getFirstNodeById($fileId); + if ($file === null || !$this->isTrack($file)) { return; } - $file = array_shift($files); - if ($file !== null and $this->isTrack($file)) { - $this->safeAddTrack($file, $userId); - } + $this->safeAddTrack($file, $userId); } public function safeAddByFolderIdUserId($folderId, $userId) { - $folders = $this->root->getById($folderId); - if (empty($folders)) { + $folder = $this->root->getUserFolder($folderId); + if ($folder === null) { return; } - $folder = array_shift($folders); - if ($folder !== null) { - $tracks = $this->gatherTrackFiles($folder, true); - foreach ($tracks as $track) { - $this->safeAddTrack($track, $userId); - } + $tracks = $this->gatherTrackFiles($folder, true); + foreach ($tracks as $track) { + $this->safeAddTrack($track, $userId); } } @@ -133,19 +128,19 @@ public function addByFolder(Node $folder) { // delete track only if it's not accessible to user anymore // it might have been shared multiple times by different users - public function safeDeleteByFileIdUserId($fileId, $userId) { + public function safeDeleteByFileIdUserId(int $fileId, string $userId): void { $userFolder = $this->root->getUserFolder($userId); - $files = $userFolder->getById($fileId); - if (!is_array($files) or count($files) === 0) { + $file = $userFolder->getFirstNodeById($fileId); + if ($file === null) { $this->deleteByFileIdUserId($fileId, $userId); } } - public function deleteByFile(Node $file) { + public function deleteByFile(Node $file): void { $this->deleteByFileId($file->getId()); } - public function deleteByFolder(Node $folder) { + public function deleteByFolder(Node $folder): void { $tracks = $this->gatherTrackFiles($folder, true); foreach ($tracks as $track) { $this->deleteByFileId($track->getId()); @@ -153,7 +148,7 @@ public function deleteByFolder(Node $folder) { } // delete folder tracks only if it's not accessible to user anymore - public function safeDeleteByFolderIdUserId($folderId, $userId) { + public function safeDeleteByFolderIdUserId(int $folderId, string $userId): void { $userFolder = $this->root->getUserFolder($userId); $folders = $userFolder->getById($folderId); if (is_array($folders) and count($folders) === 1) { @@ -196,17 +191,16 @@ private function isTrack($file) { return true; } - private function dbRowToTrack($row, $folder, $userFolder, $defaultMap, $ignoredPaths) { + private function dbRowToTrack($row, Folder $folder, $userFolder, $defaultMap, $ignoredPaths) { // avoid tracks that are not in "this map's" folder - $files = $folder->getById(intval($row['file_id'])); - if (empty($files)) { + $file = $folder->getFirstNodeById(intval($row['file_id'])); + if ($file === null) { if ($defaultMap) { $this->deleteTrackFromDB($row['id']); } return null; } - $file = array_shift($files); - if ($file === null || $file->getType() !== \OCP\Files\FileInfo::TYPE_FILE) { + if (!$file instanceof File) { if ($defaultMap) { $this->deleteTrackFromDB($row['id']); } @@ -336,11 +330,7 @@ public function getTrackFromDB($id, $userId = null) { while ($row = $req->fetch()) { if ($userId !== '' and $userId !== null) { $userFolder = $this->root->getUserFolder($userId); - $files = $userFolder->getById(intval($row['file_id'])); - if (empty($files)) { - break; - } - $file = array_shift($files); + $file = $userFolder->getFirstNodeById(intval($row['file_id'])); if ($file === null) { break; } @@ -386,11 +376,7 @@ public function getTrackByFileIDFromDB(int $fileId, ?string $userId = null) { while ($row = $req->fetch()) { if ($userId !== '' and $userId !== null) { $userFolder = $this->root->getUserFolder($userId); - $files = $userFolder->getById(intval($row['file_id'])); - if (empty($files)) { - break; - } - $file = array_shift($files); + $file = $userFolder->getFirstNodeById(intval($row['file_id'])); if ($file === null) { break; } From 9cc56850a9d8fbc05600274968e6da751a241233 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Thu, 5 Feb 2026 15:55:11 +0100 Subject: [PATCH 02/15] fix(psalm): Fix more issues Signed-off-by: Carl Schwan --- lib/Controller/DevicesController.php | 203 ++++++++------------------- lib/DB/DeviceShareMapper.php | 4 +- lib/DB/FavoriteShareMapper.php | 89 ++++-------- lib/Service/DevicesService.php | 14 +- lib/Service/MyMapsService.php | 8 +- 5 files changed, 94 insertions(+), 224 deletions(-) diff --git a/lib/Controller/DevicesController.php b/lib/Controller/DevicesController.php index c199d4d6c..144957f0d 100644 --- a/lib/Controller/DevicesController.php +++ b/lib/Controller/DevicesController.php @@ -14,86 +14,49 @@ use OCA\Maps\DB\DeviceShareMapper; use OCA\Maps\Service\DevicesService; -use OCP\App\IAppManager; use OCP\AppFramework\Controller; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\DataResponse; +use OCP\Files\File; +use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OCP\IConfig; use OCP\IDateTimeZone; -use OCP\IGroupManager; use OCP\IL10N; use OCP\IRequest; -use OCP\IServerContainer; -use OCP\IUserManager; -use OCP\Share\IManager; - -//use function \OCA\Maps\Service\endswith; class DevicesController extends Controller { + private ?Folder $userFolder = null; + private string $appVersion; - private $userId; - private $userfolder; - private $config; - private $appVersion; - private $shareManager; - private $userManager; - private $groupManager; - private $dbtype; - private $dbdblquotes; - private $defaultDeviceId; - private $l; - private $devicesService; - private $deviceShareMapper; - private $dateTimeZone; - private $root; - protected $appName; - - public function __construct($AppName, + public function __construct( + string $appName, IRequest $request, - IServerContainer $serverContainer, IConfig $config, - IManager $shareManager, - IAppManager $appManager, - IUserManager $userManager, - IGroupManager $groupManager, - IL10N $l, - DevicesService $devicesService, - DeviceShareMapper $deviceShareMapper, - IDateTimeZone $dateTimeZone, - IRootFolder $root, - $UserId) { - parent::__construct($AppName, $request); - $this->devicesService = $devicesService; - $this->deviceShareMapper = $deviceShareMapper; - $this->dateTimeZone = $dateTimeZone; - $this->appName = $AppName; + private IL10N $l, + private DevicesService $devicesService, + private DeviceShareMapper $deviceShareMapper, + private IDateTimeZone $dateTimeZone, + private IRootFolder $root, + private ?string $userId, + ) { + parent::__construct($appName, $request); $this->appVersion = $config->getAppValue('maps', 'installed_version'); - $this->userId = $UserId; - $this->userManager = $userManager; - $this->groupManager = $groupManager; - $this->l = $l; - $this->root = $root; - $this->dbtype = $config->getSystemValue('dbtype'); - // IConfig object - $this->config = $config; - if ($UserId !== '' and $UserId !== null and $serverContainer !== null) { + if ($userId !== '' && $userId !== null) { // path of user files folder relative to DATA folder - $this->userfolder = $serverContainer->getUserFolder($UserId); + $this->userFolder = $this->root->getUserFolder($userId); } - $this->shareManager = $shareManager; } /** - * @NoAdminRequired * @param ?string[] $tokens - * @param ?int $myMapId - * @return DataResponse */ - public function getDevices($tokens = null, $myMapId = null): DataResponse { + #[NoAdminRequired] + public function getDevices(?array $tokens = null, ?int $myMapId = null): DataResponse { if (is_null($tokens)) { $tokens = []; } @@ -107,9 +70,8 @@ public function getDevices($tokens = null, $myMapId = null): DataResponse { } else { $devices = []; $userFolder = $this->root->getUserFolder($this->userId); - $folders = $userFolder->getById($myMapId); - $folder = array_shift($folders); - if (is_null($folder)) { + $folder = $userFolder->getFirstNodeById($myMapId); + if (!$folder instanceof Folder) { return new DataResponse($this->l->t('Map not Found'), 404); } $shares = $this->devicesService->getSharedDevicesFromFolder($folder); @@ -122,22 +84,16 @@ public function getDevices($tokens = null, $myMapId = null): DataResponse { } /** - * @NoAdminRequired * @param string[] $tokens - * @return DataResponse */ + #[NoAdminRequired] public function getDevicesByTokens(array $tokens): DataResponse { $devices = $this->devicesService->getDevicesByTokens($tokens); return new DataResponse(array_values($devices)); } - /** - * @NoAdminRequired - * @param $id - * @param int $pruneBefore - * @return DataResponse - */ - public function getDevicePoints($id, ?int $pruneBefore = 0, ?int $limit = 10000, ?int $offset = 0, ?array $tokens = null): DataResponse { + #[NoAdminRequired] + public function getDevicePoints(int $id, ?int $pruneBefore = 0, ?int $limit = 10000, ?int $offset = 0, ?array $tokens = null): DataResponse { if (is_null($tokens)) { $points = $this->devicesService->getDevicePointsFromDB($this->userId, $id, $pruneBefore, $limit, $offset); } else { @@ -147,7 +103,6 @@ public function getDevicePoints($id, ?int $pruneBefore = 0, ?int $limit = 10000, } /** - * @NoAdminRequired * @param $lat * @param $lng * @param null $timestamp @@ -157,6 +112,7 @@ public function getDevicePoints($id, ?int $pruneBefore = 0, ?int $limit = 10000, * @param null $accuracy * @return DataResponse */ + #[NoAdminRequired] public function addDevicePoint($lat, $lng, $timestamp = null, $user_agent = null, $altitude = null, $battery = null, $accuracy = null): DataResponse { if (is_numeric($lat) and is_numeric($lng)) { $ts = $timestamp; @@ -178,19 +134,11 @@ public function addDevicePoint($lat, $lng, $timestamp = null, $user_agent = null } } - /** - * @NoAdminRequired - * @param $id - * @param $color - * @param $name - * @return DataResponse - */ - public function editDevice($id, $color, $name): DataResponse { + #[NoAdminRequired] + public function editDevice(int $id, string $color, string $name): DataResponse { $device = $this->devicesService->getDeviceFromDB($id, $this->userId); if ($device !== null) { - if ((is_string($color) && strlen($color) > 0) - || (is_string($name) && strlen($name) > 0) - ) { + if (strlen($color) > 0 || strlen($name) > 0) { $this->devicesService->editDeviceInDB($id, $color, $name); $editedDevice = $this->devicesService->getDeviceFromDB($id, $this->userId); return new DataResponse($editedDevice); @@ -202,12 +150,8 @@ public function editDevice($id, $color, $name): DataResponse { } } - /** - * @NoAdminRequired - * @param $id - * @return DataResponse - */ - public function deleteDevice($id): DataResponse { + #[NoAdminRequired] + public function deleteDevice(int $id): DataResponse { $device = $this->devicesService->getDeviceFromDB($id, $this->userId); if ($device !== null) { $this->devicesService->deleteDeviceFromDB($id); @@ -219,7 +163,6 @@ public function deleteDevice($id): DataResponse { } /** - * @NoAdminRequired * @param ?array $deviceIdList * @param int $begin * @param int $end @@ -227,6 +170,7 @@ public function deleteDevice($id): DataResponse { * @throws \OCP\Files\NotFoundException * @throws \OCP\Files\NotPermittedException */ + #[NoAdminRequired] public function exportDevices($deviceIdList, $begin, $end, bool $all = false): DataResponse { // sorry about ugly deviceIdList management: // when an empty list is passed in http request, we get null here @@ -235,13 +179,13 @@ public function exportDevices($deviceIdList, $begin, $end, bool $all = false): D } // create /Maps directory if necessary - $userFolder = $this->userfolder; + $userFolder = $this->userFolder; if (!$userFolder->nodeExists('/Maps')) { $userFolder->newFolder('Maps'); } if ($userFolder->nodeExists('/Maps')) { $mapsFolder = $userFolder->get('/Maps'); - if ($mapsFolder->getType() !== \OCP\Files\FileInfo::TYPE_FOLDER) { + if (!$mapsFolder instanceof Folder) { return new DataResponse($this->l->t('/Maps is not a directory'), 400); } elseif (!$mapsFolder->isCreatable()) { return new DataResponse($this->l->t('/Maps directory is not writeable'), 400); @@ -276,14 +220,14 @@ public function exportDevices($deviceIdList, $begin, $end, bool $all = false): D } /** - * @NoAdminRequired * @param $path * @return DataResponse * @throws \OCP\Files\InvalidPathException * @throws \OCP\Files\NotFoundException */ + #[NoAdminRequired] public function importDevices($path): DataResponse { - $userFolder = $this->userfolder; + $userFolder = $this->userFolder; $cleanpath = str_replace(['../', '..\\'], '', $path); if ($userFolder->nodeExists($cleanpath)) { @@ -291,7 +235,7 @@ public function importDevices($path): DataResponse { if ($file->getType() === \OCP\Files\FileInfo::TYPE_FILE and $file->isReadable()) { $lowerFileName = strtolower($file->getName()); - if ($this->endsWith($lowerFileName, '.gpx') or $this->endsWith($lowerFileName, '.kml') or $this->endsWith($lowerFileName, '.kmz')) { + if (str_ends_with($lowerFileName, '.gpx') || str_ends_with($lowerFileName, '.kml') || str_ends_with($lowerFileName, '.kmz')) { $nbImported = $this->devicesService->importDevices($this->userId, $file); return new DataResponse($nbImported); } else { @@ -309,71 +253,43 @@ public function importDevices($path): DataResponse { } /** - * @param $string - * @param $test - * @return bool - */ - private function endsWith($string, $test): bool { - $strlen = strlen($string); - $testlen = strlen($test); - if ($testlen > $strlen) { - return false; - } - return substr_compare($string, $test, $strlen - $testlen, $testlen) === 0; - } - - /** - * @NoAdminRequired - * @param int|null $myMapId - * @return DataResponse * @throws \OCP\Files\NotPermittedException * @throws \OC\User\NoUserException */ + #[NoAdminRequired] public function getSharedDevices(?int $myMapId = null): DataResponse { - if (is_null($myMapId) || $myMapId === '') { + if (is_null($myMapId)) { $sharedDevices = []; } else { - $folders = $this->userfolder->getById($myMapId); - $folder = array_shift($folders); - $sharedDevices = $this->devicesService->getSharedDevicesFromFolder($folder); + $folder = $this->userFolder->getFirstNodeById($myMapId); + if ($folder instanceof Folder) { + $sharedDevices = $this->devicesService->getSharedDevicesFromFolder($folder); + } } return new DataResponse($sharedDevices); } - /** - * @NoAdminRequired - * @param int $id - * @param int $timestampFrom - * @param int $timestampTo - * @return DataResponse - */ + #[NoAdminRequired] public function shareDevice(int $id, int $timestampFrom, int $timestampTo): DataResponse { $device = $this->devicesService->getDeviceFromDB($id, $this->userId); - if ($device !== null) { - $share = $this->deviceShareMapper->create($id, $timestampFrom, $timestampTo); - - if ($share === null) { - return new DataResponse($this->l->t('Error sharing device'), Http::STATUS_INTERNAL_SERVER_ERROR); - } - } else { + if ($device === null) { return new DataResponse($this->l->t('No such device'), 400); } + $share = $this->deviceShareMapper->create($id, $timestampFrom, $timestampTo); return new DataResponse($share); } /** - * @NoAdminRequired - * @param int $token - * @return DataResponse * @throws NotPermittedException * @throws NotFoundException */ - public function removeDeviceShare(int $token): DataResponse { + #[NoAdminRequired] + public function removeDeviceShare(string $token): DataResponse { try { $share = $this->deviceShareMapper->findByToken($token); - } catch (DoesNotExistException $e) { + } catch (DoesNotExistException) { throw new NotFoundException(); } $device = $this->devicesService->getDeviceFromDB($share->getDeviceId(), $this->userId); @@ -385,27 +301,24 @@ public function removeDeviceShare(int $token): DataResponse { } /** - * @NoAdminRequired - * @param string $token - * @param $targetMapId - * @return DataResponse * @throws NotFoundException */ - public function addSharedDeviceToMap(string $token, $targetMapId): DataResponse { + #[NoAdminRequired] + public function addSharedDeviceToMap(string $token, int $targetMapId): DataResponse { try { $share = $this->deviceShareMapper->findByToken($token); } catch (DoesNotExistException $e) { return new DataResponse($this->l->t('Share not Found'), 404); } - $folders = $this->userfolder->getById($targetMapId); - $folder = array_shift($folders); - if (is_null($folder)) { + $folder = $this->userFolder->getFirstNodeById($targetMapId); + if (!$folder instanceof Folder) { return new DataResponse($this->l->t('Map not Found'), 404); } try { + /** @var File $file */ $file = $folder->get('.device_shares.json'); } catch (\OCP\Files\NotFoundException $e) { - $file = $folder->newFile('.device_shares.json', $content = '[]'); + $file = $folder->newFile('.device_shares.json', '[]'); } $data = json_decode($file->getContent(), true); foreach ($data as $s) { @@ -419,15 +332,15 @@ public function addSharedDeviceToMap(string $token, $targetMapId): DataResponse } public function removeSharedDeviceFromMap(string $token, int $myMapId): DataResponse { - $folders = $this->userfolder->getById($myMapId); - $folder = array_shift($folders); - if (is_null($folder)) { + $folder = $this->userFolder->getFirstNodeById($myMapId); + if (!$folder instanceof Folder) { return new DataResponse($this->l->t('Map not Found'), 404); } try { + /** @var File $file */ $file = $folder->get('.device_shares.json'); } catch (\OCP\Files\NotFoundException $e) { - $file = $folder->newFile('.device_shares.json', $content = '[]'); + $file = $folder->newFile('.device_shares.json', '[]'); } $data = json_decode($file->getContent(), true); $shares = []; diff --git a/lib/DB/DeviceShareMapper.php b/lib/DB/DeviceShareMapper.php index 8a2238aea..340ff1bdb 100644 --- a/lib/DB/DeviceShareMapper.php +++ b/lib/DB/DeviceShareMapper.php @@ -50,12 +50,10 @@ public function __construct(IDBConnection $db, ISecureRandom $secureRandom, IRoo } /** - * @param string $token - * @return DeviceShare|null * @throws DoesNotExistException * @throws MultipleObjectsReturnedException */ - public function findByToken($token) { + public function findByToken(string $token): DeviceShare { $qb = $this->db->getQueryBuilder(); $qb->select('*') diff --git a/lib/DB/FavoriteShareMapper.php b/lib/DB/FavoriteShareMapper.php index 105be5fdd..b4d39a8d6 100644 --- a/lib/DB/FavoriteShareMapper.php +++ b/lib/DB/FavoriteShareMapper.php @@ -26,10 +26,11 @@ use OC\Share\Constants; use OCP\AppFramework\Db\DoesNotExistException; -use OCP\AppFramework\Db\Entity; use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\AppFramework\Db\QBMapper; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Files\File; +use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\IDBConnection; @@ -37,24 +38,19 @@ /** @template-extends QBMapper */ class FavoriteShareMapper extends QBMapper { - /* @var ISecureRandom */ - private $secureRandom; - private $root; - - public function __construct(IDBConnection $db, ISecureRandom $secureRandom, IRootFolder $root) { + public function __construct( + IDBConnection $db, + private ISecureRandom $secureRandom, + private IRootFolder $root, + ) { parent::__construct($db, 'maps_favorite_shares'); - - $this->secureRandom = $secureRandom; - $this->root = $root; } /** - * @param $token - * @return Entity|null * @throws DoesNotExistException * @throws MultipleObjectsReturnedException */ - public function findByToken($token) { + public function findByToken(string $token): FavoriteShare { $qb = $this->db->getQueryBuilder(); $qb->select('*') @@ -66,12 +62,7 @@ public function findByToken($token) { return $this->findEntity($qb); } - /** - * @param $owner - * @param $category - * @return Entity - */ - public function create($owner, $category) { + public function create(string $owner, string $category): FavoriteShare { $token = $this->secureRandom->generate( Constants::TOKEN_LENGTH, ISecureRandom::CHAR_HUMAN_READABLE @@ -86,10 +77,9 @@ public function create($owner, $category) { } /** - * @param $owner - * @return array|Entity[] + * @return FavoriteShare[] */ - public function findAllByOwner($owner) { + public function findAllByOwner(string $owner): array { $qb = $this->db->getQueryBuilder(); $qb->select('*') @@ -102,38 +92,30 @@ public function findAllByOwner($owner) { } /** - * @param $userId - * @param $mapId - * @return array|mixed * @throws \OCP\Files\NotPermittedException * @throws \OC\User\NoUserException */ - public function findAllByMapId($userId, $mapId) { + public function findAllByMapId(string $userId, int $mapId): array { $userFolder = $this->root->getUserFolder($userId); - $folders = $userFolder->getById($mapId); + $folder = $userFolder->getFirstNodeById($mapId); $shares = []; - if (empty($folders)) { - return $shares; - } - $folder = array_shift($folders); - if ($folder === null) { + if (!$folder instanceof Folder) { return $shares; } return $this->findAllByFolder($folder); } /** - * @param $folder - * @param $isCreatable - * @return mixed * @throws NotFoundException */ - public function findAllByFolder($folder, $isCreatable = true) { + public function findAllByFolder(Folder $folder, bool $isCreatable = true): array { try { + /** @var File $file */ $file = $folder->get('.favorite_shares.json'); } catch (NotFoundException $e) { if ($isCreatable) { - $file = $folder->newFile('.favorite_shares.json', $content = '[]'); + $folder->newFile('.favorite_shares.json', '[]'); + return []; } else { throw new NotFoundException(); } @@ -142,13 +124,10 @@ public function findAllByFolder($folder, $isCreatable = true) { } /** - * @param $owner - * @param $category - * @return Entity * @throws DoesNotExistException * @throws MultipleObjectsReturnedException */ - public function findByOwnerAndCategory($owner, $category) { + public function findByOwnerAndCategory(string $owner, string $category): FavoriteShare { $qb = $this->db->getQueryBuilder(); $qb->select('*') @@ -163,14 +142,12 @@ public function findByOwnerAndCategory($owner, $category) { } /** - * @param $userId - * @param $mapId * @param $category * @return mixed|null * @throws \OCP\Files\NotPermittedException * @throws \OC\User\NoUserException */ - public function findByMapIdAndCategory($userId, $mapId, $category) { + public function findByMapIdAndCategory(string $userId, int $mapId, $category) { $shares = $this->findAllByMapId($userId, $mapId); foreach ($shares as $share) { if ($share->category === $category) { @@ -180,16 +157,12 @@ public function findByMapIdAndCategory($userId, $mapId, $category) { return null; } - public function removeByMapIdAndCategory($userId, $mapId, $category) { + public function removeByMapIdAndCategory(string $userId, int $mapId, $category) { $userFolder = $this->root->getUserFolder($userId); - $folders = $userFolder->getById($mapId); + $folder = $userFolder->getFirstNodeById($mapId); $shares = []; $deleted = null; - if (empty($folders)) { - return $deleted; - } - $folder = array_shift($folders); - if ($folder === null) { + if (!$folder instanceof Folder) { return $deleted; } try { @@ -210,13 +183,8 @@ public function removeByMapIdAndCategory($userId, $mapId, $category) { return $deleted; } - /** - * @param $owner - * @param $category - * @return Entity|null - */ - public function findOrCreateByOwnerAndCategory($owner, $category) { - /* @var Entity */ + public function findOrCreateByOwnerAndCategory(string $owner, string $category): ?FavoriteShare { + /* @var ?FavoriteShare $entity */ $entity = null; try { @@ -229,12 +197,7 @@ public function findOrCreateByOwnerAndCategory($owner, $category) { return $entity; } - /** - * @param $owner - * @param $category - * @return bool - */ - public function removeByOwnerAndCategory($owner, $category) { + public function removeByOwnerAndCategory(string $owner, string $category): bool { try { $entity = $this->findByOwnerAndCategory($owner, $category); } catch (DoesNotExistException|MultipleObjectsReturnedException $e) { diff --git a/lib/Service/DevicesService.php b/lib/Service/DevicesService.php index 80ea39a67..986c04d95 100644 --- a/lib/Service/DevicesService.php +++ b/lib/Service/DevicesService.php @@ -15,6 +15,8 @@ use OC\Archive\ZIP; use OCP\DB\Exception; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Files\File; +use OCP\Files\Folder; use OCP\Files\NotFoundException; use OCP\IDBConnection; use OCP\IL10N; @@ -112,15 +114,10 @@ public function getDevicesByTokens(array $tokens) { } /** - * @param $userId - * @param $deviceId - * @param int|null $pruneBefore - * @param int|null $limit - * @param int|null $offset * @return array * @throws \OCP\DB\Exception */ - public function getDevicePointsFromDB($userId, $deviceId, ?int $pruneBefore = 0, ?int $limit = null, ?int $offset = null) { + public function getDevicePointsFromDB(string $userId, int $deviceId, ?int $pruneBefore = 0, ?int $limit = null, ?int $offset = null) { $qb = $this->dbconnection->getQueryBuilder(); // get coordinates $qb->selectDistinct(['p.id', 'lat', 'lng', 'timestamp', 'altitude', 'accuracy', 'battery']) @@ -768,13 +765,12 @@ private function endswith($string, $test) { } /** - * @param $folder - * @param bool $isCreatable * @return mixed * @throws NotFoundException */ - public function getSharedDevicesFromFolder($folder, bool $isCreatable = true) { + public function getSharedDevicesFromFolder(Folder $folder, bool $isCreatable = true) { try { + /** @var File $file */ $file = $folder->get('.device_shares.json'); } catch (NotFoundException $e) { if ($isCreatable) { diff --git a/lib/Service/MyMapsService.php b/lib/Service/MyMapsService.php index 54286e467..0308a2a0e 100644 --- a/lib/Service/MyMapsService.php +++ b/lib/Service/MyMapsService.php @@ -15,6 +15,7 @@ use OC\Files\Search\SearchComparison; use OC\Files\Search\SearchQuery; use OC\User\NoUserException; +use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; @@ -174,12 +175,12 @@ public function getMyMap(int $id, string $userId) { public function updateMyMap($id, $values, $userId) { $userFolder = $this->root->getUserFolder($userId); - $folders = $userFolder->getById($id); - $folder = array_shift($folders); + $folder = $userFolder->getFirstNodeById($id); if (!($folder instanceof Folder)) { return []; } try { + /** @var File $file */ $file = $folder->get('.index.maps'); } catch (NotFoundException $e) { $file = $folder->newFile('.index.maps', '{}'); @@ -216,8 +217,7 @@ public function updateMyMap($id, $values, $userId) { public function deleteMyMap($id, $userId) { $userFolder = $this->root->getUserFolder($userId); - $folders = $userFolder->getById($id); - $folder = array_shift($folders); + $folder = $userFolder->getFirstNodeById($id); if (!($folder instanceof Folder)) { return 1; } From b44957046e54f07fc9e76091a9aa36e3a0e5c623 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Fri, 6 Feb 2026 19:29:36 +0100 Subject: [PATCH 03/15] refactor: Modernize a bit the code in the tests Signed-off-by: Carl Schwan --- lib/AppInfo/Application.php | 15 +- lib/BackgroundJob/UpdatePhotoByFileJob.php | 29 +-- lib/Controller/ContactsController.php | 16 +- lib/Controller/DevicesController.php | 3 +- lib/Controller/FavoritesController.php | 115 +++++------- lib/Controller/PageController.php | 2 +- lib/Controller/PhotosController.php | 2 +- .../PublicFavoritesApiController.php | 37 +--- lib/Controller/PublicFavoritesController.php | 145 +++++---------- lib/Controller/PublicTracksController.php | 8 - lib/Controller/RoutingController.php | 76 +++----- lib/Controller/TracksController.php | 168 ++++++------------ lib/Hooks/FileHooks.php | 24 +-- lib/Service/FavoritesService.php | 45 ++--- lib/Service/PhotofilesService.php | 54 +++--- lib/Service/TracksService.php | 69 ++++--- .../Controller/ContactsControllerTest.php | 113 ++++-------- .../Controller/DevicesApiControllerTest.php | 10 -- .../Unit/Controller/DevicesControllerTest.php | 107 ++++------- .../Controller/FavoritesApiControllerTest.php | 10 -- .../Controller/FavoritesControllerTest.php | 133 +++++++------- .../Unit/Controller/PhotosControllerTest.php | 3 +- .../PublicFavoritesApiControllerTest.php | 54 +++--- .../Unit/Controller/TracksControllerTest.php | 131 +++++--------- 24 files changed, 486 insertions(+), 883 deletions(-) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 8e84b47e4..4c76bc4b4 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -31,8 +31,10 @@ use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\AppFramework\Http\EmptyFeaturePolicy; use OCP\EventDispatcher\IEventDispatcher; -use OCP\IServerContainer; +use OCP\Files\IRootFolder; +use OCP\Lock\ILockingProvider; use OCP\Security\FeaturePolicy\AddFeaturePolicyEvent; +use OCP\Server; class Application extends App implements IBootstrap { public const APP_ID = 'maps'; @@ -74,11 +76,10 @@ public function boot(IBootContext $context): void { // ... boot logic goes here ... $context->getAppContainer()->registerService('FileHooks', function ($c) { return new FileHooks( - $c->query(IServerContainer::class)->getRootFolder(), - \OCP\Server::get(PhotofilesService::class), - \OCP\Server::get(TracksService::class), - $c->query('AppName'), - $c->query(IServerContainer::class)->getLockingProvider() + Server::get(IRootFolder::class), + Server::get(PhotofilesService::class), + Server::get(TracksService::class), + Server::get(ILockingProvider::class), ); }); @@ -87,7 +88,7 @@ public function boot(IBootContext $context): void { $this->registerFeaturePolicy(); } - private function registerFeaturePolicy() { + private function registerFeaturePolicy(): void { $dispatcher = $this->getContainer()->getServer()->get(IEventDispatcher::class); $dispatcher->addListener(AddFeaturePolicyEvent::class, function (AddFeaturePolicyEvent $e) { diff --git a/lib/BackgroundJob/UpdatePhotoByFileJob.php b/lib/BackgroundJob/UpdatePhotoByFileJob.php index c4e72db14..436112959 100644 --- a/lib/BackgroundJob/UpdatePhotoByFileJob.php +++ b/lib/BackgroundJob/UpdatePhotoByFileJob.php @@ -15,51 +15,36 @@ use OCA\Maps\Service\PhotofilesService; use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\QueuedJob; +use OCP\Files\File; use OCP\Files\IRootFolder; use OCP\ICache; use OCP\ICacheFactory; class UpdatePhotoByFileJob extends QueuedJob { - - /** @var PhotofilesService */ - private PhotofilesService $photofilesService; - - /** @var IRootFolder */ - private IRootFolder $root; - - /** @var ICacheFactory */ - private ICacheFactory $cacheFactory; - - /** @var ICache */ private ICache $backgroundJobCache; /** * UserInstallScanJob constructor. * * A QueuedJob to scan user storage for photos and tracks - * */ public function __construct( ITimeFactory $timeFactory, - IRootFolder $root, - PhotofilesService $photofilesService, - ICacheFactory $cacheFactory, + private IRootFolder $root, + private PhotofilesService $photofilesService, + private ICacheFactory $cacheFactory, ) { parent::__construct($timeFactory); - $this->photofilesService = $photofilesService; - $this->root = $root; - $this->cacheFactory = $cacheFactory; $this->backgroundJobCache = $this->cacheFactory->createDistributed('maps:background-jobs'); } - public function run($argument) { + public function run($argument): void { $userFolder = $this->root->getUserFolder($argument['userId']); - $files = $userFolder->getById($argument['fileId']); - if (empty($files)) { + $file = $userFolder->getFirstNodeById($argument['fileId']); + if (!$file instanceof File) { return; } - $file = array_shift($files); $this->photofilesService->updateByFileNow($file); $counter = $this->backgroundJobCache->get('recentlyUpdated:' . $argument['userId']) ?? 0; diff --git a/lib/Controller/ContactsController.php b/lib/Controller/ContactsController.php index cc7c0a499..ea359686d 100644 --- a/lib/Controller/ContactsController.php +++ b/lib/Controller/ContactsController.php @@ -61,7 +61,7 @@ private function geoAsFloatArray(string $geo): array { /** * check if geographical address is duplicated - * @param list containing contact's previous different addresses + * @param list $prevGeo containing contact's previous different addresses * @param array $geo contact's address to check * @return integer : -1 if address is new, index of duplicated address in other cases */ @@ -97,10 +97,10 @@ private function getDistance(array $coordsA, array $coordsB) { $latB = deg2rad($coordsB[0]); $lonB = deg2rad($coordsB[1]); $earthRadius = 6378137; // in m - $dlon = ($lonB - $lonA) / 2; - $dlat = ($latB - $latA) / 2; + $dlon = ($lonB - $lonA) / 2.0; + $dlat = ($latB - $latA) / 2.0; $a = (sin($dlat) * sin($dlat)) + cos($latA) * cos($latB) * (sin($dlon) * sin($dlon)); - $d = 2 * atan2(sqrt($a), sqrt(1 - $a)); + $d = 2.0 * atan2(sqrt($a), sqrt(1.0 - $a)); return $d * $earthRadius; } @@ -184,7 +184,7 @@ public function getContacts(?int $myMapId = null): DataResponse { if (isset($adr->parameters()['TYPE'])) { $adrtype = $adr->parameters()['TYPE']->getValue(); } - if (is_string($geo) && strlen($geo) > 1) { + if (strlen($geo) > 1) { if ($duplicatedIndex < 0) { array_push($prevGeo, $geof); array_push($prevRes, count($result)); // Add index of new item so that we can update the ADRTYPE in case of duplicate address @@ -262,7 +262,7 @@ public function getContacts(?int $myMapId = null): DataResponse { if (isset($adr->parameters()['TYPE'])) { $adrtype = $adr->parameters()['TYPE']->getValue(); } - if (is_string($geo) && strlen($geo) > 1) { + if (strlen($geo) > 1) { if ($duplicatedIndex < 0) { array_push($prevGeo, $geof); array_push($prevRes, count($result)); // Add index of new item so that we can update the ADRTYPE in case of duplicate address @@ -410,7 +410,7 @@ public function placeContact( ?string $address_string = null, ?int $fileId = null, ?int $myMapId = null): DataResponse { - if (is_null($myMapId) || $myMapId === '') { + if (is_null($myMapId)) { // do not edit 'user' contact even myself if (strcmp($uri, 'Database:' . $uid . '.vcf') === 0 or strcmp($uid, $this->userId) === 0 @@ -598,7 +598,7 @@ private function setAddressCoordinates(float $lat, float $lng, string $adr, stri $result = $req->fetchAll(); $req->closeCursor(); $qb = $this->dbconnection->getQueryBuilder(); - if ($result and count($result) > 0) { + if (count($result) > 0) { $id = $result[0]['id']; $qb->update('maps_address_geo') ->set('lat', $qb->createNamedParameter($lat, IQueryBuilder::PARAM_STR)) diff --git a/lib/Controller/DevicesController.php b/lib/Controller/DevicesController.php index 144957f0d..16c1b755a 100644 --- a/lib/Controller/DevicesController.php +++ b/lib/Controller/DevicesController.php @@ -232,8 +232,7 @@ public function importDevices($path): DataResponse { if ($userFolder->nodeExists($cleanpath)) { $file = $userFolder->get($cleanpath); - if ($file->getType() === \OCP\Files\FileInfo::TYPE_FILE - and $file->isReadable()) { + if ($file instanceof File && $file->isReadable()) { $lowerFileName = strtolower($file->getName()); if (str_ends_with($lowerFileName, '.gpx') || str_ends_with($lowerFileName, '.kml') || str_ends_with($lowerFileName, '.kmz')) { $nbImported = $this->devicesService->importDevices($this->userId, $file); diff --git a/lib/Controller/FavoritesController.php b/lib/Controller/FavoritesController.php index 0bc32ae72..016da5f66 100644 --- a/lib/Controller/FavoritesController.php +++ b/lib/Controller/FavoritesController.php @@ -137,30 +137,28 @@ public function getFavorites(?int $myMapId = null): DataResponse { * @throws \OCP\Files\NotPermittedException */ #[NoAdminRequired] - public function addFavorite(?string $name, float $lat, float $lng, ?string $category, ?string $comment, ?string $extensions, ?int $myMapId = null): DataResponse { - if (is_numeric($lat) && is_numeric($lng)) { - if (is_null($myMapId) || $myMapId === '') { - $favoriteId = $this->favoritesService->addFavoriteToDB($this->userId, $name, $lat, $lng, $category, $comment, $extensions); - $favorite = $this->favoritesService->getFavoriteFromDB($favoriteId); - return new DataResponse($favorite); - } else { - $folders = $this->userFolder->getById($myMapId); - if (!empty($folders) && $this->userFolder->getId() === $myMapId) { - $folders[] = $this->userFolder; - } - $folder = array_shift($folders); - if (!($folder instanceof Folder)) { - return new DataResponse('Map not found', 404); - } - $file = $this->getJSONFavoritesFile($folder); - $favoriteId = $this->favoritesService->addFavoriteToJSON($file, $name, $lat, $lng, $category, $comment, $extensions); - $favorite = $this->favoritesService->getFavoriteFromJSON($file, $favoriteId); - return new DataResponse($favorite); - } - - } else { + public function addFavorite(?string $name, ?float $lat, ?float $lng, ?string $category, ?string $comment, ?string $extensions, ?int $myMapId = null): DataResponse { + if (!is_numeric($lat) || !is_numeric($lng)) { return new DataResponse($this->l->t('Invalid values'), 400); } + if (is_null($myMapId)) { + $favoriteId = $this->favoritesService->addFavoriteToDB($this->userId, $name, $lat, $lng, $category, $comment, $extensions); + $favorite = $this->favoritesService->getFavoriteFromDB($favoriteId); + return new DataResponse($favorite); + } else { + $folders = $this->userFolder->getById($myMapId); + if (!empty($folders) && $this->userFolder->getId() === $myMapId) { + $folders[] = $this->userFolder; + } + $folder = array_shift($folders); + if (!($folder instanceof Folder)) { + return new DataResponse('Map not found', 404); + } + $file = $this->getJSONFavoritesFile($folder); + $favoriteId = $this->favoritesService->addFavoriteToJSON($file, $name, $lat, $lng, $category, $comment, $extensions); + $favorite = $this->favoritesService->getFavoriteFromJSON($file, $favoriteId); + return new DataResponse($favorite); + } } /** @@ -173,7 +171,7 @@ public function addFavorite(?string $name, float $lat, float $lng, ?string $cate */ #[NoAdminRequired] public function addFavorites(array $favorites, ?int $myMapId = null): DataResponse { - if (is_null($myMapId) || $myMapId === '') { + if (is_null($myMapId)) { $favoritesAfter = []; foreach ($favorites as $favorite) { if (is_numeric($favorite->lat) && is_numeric($favorite->lng)) { @@ -206,62 +204,35 @@ public function addFavorites(array $favorites, ?int $myMapId = null): DataRespon } /** - * @param int $id - * @param string|null $name - * @param float $lat - * @param float $lng - * @param string|null $category - * @param string|null $comment - * @param string|null $extensions - * @param int|null $myMapId - * @return DataResponse * @throws \OCP\Files\NotPermittedException */ #[NoAdminRequired] - public function editFavorite(int $id, ?string $name, float $lat, float $lng, ?string $category, ?string $comment, ?string $extensions, ?int $myMapId = null): DataResponse { - if (is_null($myMapId) || $myMapId === '') { + public function editFavorite(int $id, ?string $name, ?float $lat, ?float $lng, ?string $category, ?string $comment, ?string $extensions, ?int $myMapId = null): DataResponse { + if (is_null($myMapId)) { $favorite = $this->favoritesService->getFavoriteFromDB($id, $this->userId); if ($favorite !== null) { - if (($lat === null || is_numeric($lat)) - && ($lng === null || is_numeric($lng)) - ) { - $this->favoritesService->editFavoriteInDB($id, $name, $lat, $lng, $category, $comment, $extensions); - $editedFavorite = $this->favoritesService->getFavoriteFromDB($id); - return new DataResponse($editedFavorite); - } else { - return new DataResponse($this->l->t('invalid values'), 400); - } - } else { - return new DataResponse($this->l->t('no such favorite'), 400); - } - } else { - $folder = $this->userFolder->getFirstNodeById($myMapId); - if (!$folder instanceof Folder) { - return new DataResponse('Map not found', 404); - } - $file = $this->getJSONFavoritesFile($folder); - $favorite = $this->favoritesService->getFavoriteFromJSON($file, $id, $this->userId); - if ($favorite !== null) { - if (($lat === null || is_numeric($lat)) - && ($lng === null || is_numeric($lng)) - ) { - $this->favoritesService->editFavoriteInJSON($file, $id, $name, $lat, $lng, $category, $comment, $extensions); - $editedFavorite = $this->favoritesService->getFavoriteFromJSON($file, $id); - return new DataResponse($editedFavorite); - } else { - return new DataResponse($this->l->t('invalid values'), 400); - } - } else { - return new DataResponse($this->l->t('no such favorite'), 400); + $this->favoritesService->editFavoriteInDB($id, $name, $lat, $lng, $category, $comment, $extensions); + $editedFavorite = $this->favoritesService->getFavoriteFromDB($id); + return new DataResponse($editedFavorite); } + return new DataResponse($this->l->t('no such favorite'), 400); } + + $folder = $this->userFolder->getFirstNodeById($myMapId); + if (!$folder instanceof Folder) { + return new DataResponse('Map not found', 404); + } + $file = $this->getJSONFavoritesFile($folder); + $favorite = $this->favoritesService->getFavoriteFromJSON($file, $id, $this->userId); + if ($favorite === null) { + return new DataResponse($this->l->t('no such favorite'), 400); + } + $this->favoritesService->editFavoriteInJSON($file, $id, $name, $lat, $lng, $category, $comment, $extensions); + $editedFavorite = $this->favoritesService->getFavoriteFromJSON($file, $id); + return new DataResponse($editedFavorite); } /** - * @param array $categories - * @param string $newName - * @param int|null $myMapId - * @return DataResponse * @throws \OCP\DB\Exception * @throws \OCP\Files\NotPermittedException */ @@ -269,7 +240,7 @@ public function editFavorite(int $id, ?string $name, float $lat, float $lng, ?st public function renameCategories(array $categories, string $newName, ?int $myMapId = null): DataResponse { if (is_array($categories)) { foreach ($categories as $cat) { - if (is_null($myMapId) || $myMapId === '') { + if (is_null($myMapId)) { $this->favoritesService->renameCategoryInDB($this->userId, $cat, $newName); // Rename share if one exists @@ -300,7 +271,7 @@ public function renameCategories(array $categories, string $newName, ?int $myMap */ #[NoAdminRequired] public function deleteFavorite(int $id, ?int $myMapId = null): DataResponse { - if (is_null($myMapId) || $myMapId === '') { + if (is_null($myMapId)) { $favorite = $this->favoritesService->getFavoriteFromDB($id, $this->userId); if ($favorite !== null) { $this->favoritesService->deleteFavoriteFromDB($id); @@ -327,7 +298,7 @@ public function deleteFavorite(int $id, ?int $myMapId = null): DataResponse { */ #[NoAdminRequired] public function deleteFavorites(array $ids, ?int $myMapId = null): DataResponse { - if (is_null($myMapId) || $myMapId === '') { + if (is_null($myMapId)) { $this->favoritesService->deleteFavoritesFromDB($ids, $this->userId); } else { $folder = $this->userFolder->getFirstNodeById($myMapId); diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php index d73f36bb2..d9a3d856b 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -29,7 +29,7 @@ class PageController extends Controller { public function __construct( string $appName, IRequest $request, - private string $userId, + private ?string $userId, private IEventDispatcher $eventDispatcher, private IConfig $config, private IInitialState $initialState, diff --git a/lib/Controller/PhotosController.php b/lib/Controller/PhotosController.php index fb1abaefa..d177e67c5 100644 --- a/lib/Controller/PhotosController.php +++ b/lib/Controller/PhotosController.php @@ -81,7 +81,7 @@ public function getNonLocalizedPhotos(?int $myMapId = null, ?string $timezone = $result = $this->geophotoService->getNonLocalized($this->userId, $userFolder, $respectNoMediaAndNoimage ?? true, $hideImagesOnCustomMaps ?? false, $hideImagesInMapsFolder ?? true, $timezone, $limit, $offset); } else { $folder = $userFolder->getFirstNodeById($myMapId); - if ($folder instanceof Folder) { + if (!$folder instanceof Folder) { throw new NotFoundException('Could find map with mapid: ' . $myMapId); } $result = $this->geophotoService->getNonLocalized($this->userId, $folder, $respectNoMediaAndNoimage ?? true, $hideImagesOnCustomMaps ?? false, $hideImagesInMapsFolder ?? false, $timezone, $limit, $offset); diff --git a/lib/Controller/PublicFavoritesApiController.php b/lib/Controller/PublicFavoritesApiController.php index 8285d1adc..f253256e3 100644 --- a/lib/Controller/PublicFavoritesApiController.php +++ b/lib/Controller/PublicFavoritesApiController.php @@ -30,45 +30,31 @@ use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\PublicShareController; use OCP\IRequest; use OCP\ISession; class PublicFavoritesApiController extends PublicShareController { - /* @var FavoritesService */ - private $favoritesService; - - /* @var FavoriteShareMapper */ - private $favoriteShareMapper; - public function __construct( $appName, IRequest $request, ISession $session, - FavoritesService $favoritesService, - FavoriteShareMapper $favoriteShareMapper, + private FavoritesService $favoritesService, + private FavoriteShareMapper $favoriteShareMapper, ) { parent::__construct($appName, $request, $session); - - $this->favoriteShareMapper = $favoriteShareMapper; - $this->favoritesService = $favoritesService; } public function getPasswordHash(): string { return ''; } - /** - * @return bool - */ protected function isPasswordProtected(): bool { return false; } - /** - * @return bool - */ public function isValidToken(): bool { try { $this->favoriteShareMapper->findByToken($this->getToken()); @@ -79,10 +65,7 @@ public function isValidToken(): bool { return true; } - /** - * @return bool - */ - public function canEdit(): bool { + /* public function canEdit(): bool { try { $share = $this->favoriteShareMapper->findByToken($this->getToken()); } catch (DoesNotExistException|MultipleObjectsReturnedException $e) { @@ -90,19 +73,15 @@ public function canEdit(): bool { } return $share->getAllowEdits(); - } + } */ - /** - * @PublicPage - * - * @return DataResponse - */ + #[PublicPage] public function getFavorites(): DataResponse { try { $share = $this->favoriteShareMapper->findByToken($this->getToken()); - } catch (DoesNotExistException $e) { + } catch (DoesNotExistException) { return new DataResponse([], Http::STATUS_NOT_FOUND); - } catch (MultipleObjectsReturnedException $e) { + } catch (MultipleObjectsReturnedException) { return new DataResponse([], Http::STATUS_INTERNAL_SERVER_ERROR); } diff --git a/lib/Controller/PublicFavoritesController.php b/lib/Controller/PublicFavoritesController.php index 2df8f4c12..5365f927d 100644 --- a/lib/Controller/PublicFavoritesController.php +++ b/lib/Controller/PublicFavoritesController.php @@ -16,67 +16,44 @@ use OCA\Maps\DB\FavoriteShareMapper; use OCA\Maps\Service\FavoritesService; -use OCP\App\IAppManager; +use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\DataResponse; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Folder; +use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OCP\IConfig; -use OCP\IDateTimeZone; -use OCP\IGroupManager; use OCP\IInitialStateService; use OCP\IL10N; use OCP\IRequest; -use OCP\IServerContainer; use OCP\ISession; use OCP\IURLGenerator; use OCP\IUserManager; use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IManager; +use OCP\Share\IShare; class PublicFavoritesController extends PublicPageController { - - private string $appVersion; - private IL10N $l; - private FavoritesService $favoritesService; - private IDateTimeZone $dateTimeZone; private ?string $defaultFavoritsJSON; - protected $appName; - protected $groupManager; - - /* @var FavoriteShareMapper */ - private $favoriteShareMapper; public function __construct( string $appName, IRequest $request, ISession $session, IURLGenerator $urlGenerator, - IServerContainer $serverContainer, IConfig $config, IInitialStateService $initialStateService, IManager $shareManager, - IAppManager $appManager, IUserManager $userManager, - IGroupManager $groupManager, - IL10N $l, - FavoritesService $favoritesService, - IDateTimeZone $dateTimeZone, - FavoriteShareMapper $favoriteShareMapper, + private IL10N $l, + private FavoritesService $favoritesService, + private FavoriteShareMapper $favoriteShareMapper, IEventDispatcher $eventDispatcher, ) { parent::__construct($appName, $request, $session, $urlGenerator, $eventDispatcher, $config, $initialStateService, $shareManager, $userManager); - $this->favoritesService = $favoritesService; - $this->dateTimeZone = $dateTimeZone; - $this->appName = $appName; - $this->appVersion = $config->getAppValue('maps', 'installed_version'); $this->userManager = $userManager; - $this->groupManager = $groupManager; - $this->l = $l; - $this->config = $config; $this->shareManager = $shareManager; - $this->favoriteShareMapper = $favoriteShareMapper; $this->defaultFavoritsJSON = json_encode([ 'type' => 'FeatureCollection', 'features' => [] @@ -85,10 +62,8 @@ public function __construct( /** * Validate the permissions of the share - * - * @return bool */ - private function validateShare(\OCP\Share\IShare $share) { + private function validateShare(IShare $share): bool { // If the owner is disabled no access to the link is granted $owner = $this->userManager->get($share->getShareOwner()); if ($owner === null || !$owner->isEnabled()) { @@ -105,10 +80,9 @@ private function validateShare(\OCP\Share\IShare $share) { } /** - * @return \OCP\Share\IShare * @throws NotFoundException */ - private function getShare() { + private function getShare(): IShare { // Check whether share exists try { $share = $this->shareManager->getShareByToken($this->getToken()); @@ -124,7 +98,7 @@ private function getShare() { } /** - * @return \OCP\Files\File|\OCP\Files\Folder + * @return \OCP\Files\File|Folder * @throws NotFoundException */ private function getShareNode() { @@ -136,12 +110,9 @@ private function getShareNode() { } /** - * @param Folder $folder - * @param $isCreatable - * @return mixed * @throws NotPermittedException */ - private function getJSONFavoritesFile(\OCP\Files\Folder $folder, $isCreatable): \OCP\Files\Node { + private function getJSONFavoritesFile(Folder $folder, bool $isCreatable): Node { try { $file = $folder->get('.favorites.json'); } catch (NotFoundException $e) { @@ -156,11 +127,10 @@ private function getJSONFavoritesFile(\OCP\Files\Folder $folder, $isCreatable): } /** - * @PublicPage - * @return DataResponse * @throws NotFoundException * @throws NotPermittedException */ + #[PublicPage] public function getFavorites(): DataResponse { $share = $this->getShare(); $permissions = $share->getPermissions(); @@ -184,18 +154,11 @@ public function getFavorites(): DataResponse { } /** - * @PublicPage - * @param string|null $name - * @param float $lat - * @param float $lng - * @param string|null $category - * @param string|null $comment - * @param string|null $extensions - * @return DataResponse * @throws NotFoundException * @throws NotPermittedException * @throws \OCP\Files\InvalidPathException */ + #[PublicPage] public function addFavorite(?string $name, float $lat, float $lng, ?string $category, ?string $comment, ?string $extensions): DataResponse { if (is_numeric($lat) && is_numeric($lng)) { $share = $this->getShare(); @@ -218,13 +181,11 @@ public function addFavorite(?string $name, float $lat, float $lng, ?string $cate } /** - * @PublicPage - * @param array $favorites - * @return DataResponse * @throws NotFoundException * @throws NotPermittedException * @throws \OCP\Files\InvalidPathException */ + #[PublicPage] public function addFavorites(array $favorites): DataResponse { $share = $this->getShare(); $permissions = $share->getPermissions(); @@ -248,84 +209,60 @@ public function addFavorites(array $favorites): DataResponse { } /** - * @PublicPage - * @param int $id - * @param string|null $name - * @param float $lat - * @param float $lng - * @param string|null $category - * @param string|null $comment - * @param string|null $extensions - * @return DataResponse * @throws NotFoundException * @throws NotPermittedException * @throws \OCP\Files\InvalidPathException */ - public function editFavorite(int $id, ?string $name, float $lat, float $lng, ?string $category, ?string $comment, ?string $extensions): DataResponse { + #[PublicPage] + public function editFavorite(int $id, ?string $name, ?float $lat, ?float $lng, ?string $category, ?string $comment, ?string $extensions): DataResponse { $share = $this->getShare(); $permissions = $share->getPermissions(); $folder = $this->getShareNode(); $isCreatable = ($permissions & (1 << 2)) && $folder->isCreatable(); $file = $this->getJSONFavoritesFile($folder, $isCreatable); $isUpdateable = ($permissions & (1 << 1)) && $file->isUpdateable(); - if ($isUpdateable) { - $favorite = $this->favoritesService->getFavoriteFromJSON($file, $id); - if ($favorite !== null) { - if (($lat === null || is_numeric($lat)) - && ($lng === null || is_numeric($lng)) - ) { - $this->favoritesService->editFavoriteInJSON($file, $id, $name, $lat, $lng, $category, $comment, $extensions); - $editedFavorite = $this->favoritesService->getFavoriteFromJSON($file, $id); - $editedFavorite['isDeletable'] = ($permissions & (1 << 3)) && $editedFavorite['isDeletable']; - return new DataResponse($editedFavorite); - } else { - return new DataResponse($this->l->t('invalid values'), 400); - } - } else { - return new DataResponse($this->l->t('no such favorite'), 400); - } - } else { + if (!$isUpdateable) { throw new NotPermittedException(); } + $favorite = $this->favoritesService->getFavoriteFromJSON($file, $id); + if ($favorite === null) { + return new DataResponse($this->l->t('no such favorite'), 400); + } + $this->favoritesService->editFavoriteInJSON($file, $id, $name, $lat, $lng, $category, $comment, $extensions); + $editedFavorite = $this->favoritesService->getFavoriteFromJSON($file, $id); + $editedFavorite['isDeletable'] = ($permissions & (1 << 3)) && $editedFavorite['isDeletable']; + return new DataResponse($editedFavorite); } /** - * @PublicPage - * @param array $categories - * @param string $newName - * @return DataResponse * @throws NotFoundException * @throws NotPermittedException * @throws \OCP\Files\InvalidPathException */ + #[PublicPage] public function renameCategories(array $categories, string $newName): DataResponse { - if (is_array($categories)) { - $share = $this->getShare(); - $permissions = $share->getPermissions(); - $folder = $this->getShareNode(); - $isCreatable = ($permissions & (1 << 2)) && $folder->isCreatable(); - $file = $this->getJSONFavoritesFile($folder, $isCreatable); - $isUpdateable = ($permissions & (1 << 1)) && $file->isUpdateable(); - if ($isUpdateable) { - foreach ($categories as $cat) { - $this->favoritesService->renameCategoryInJSON($file, $cat, $newName); - } - } else { - throw new NotPermittedException(); + $share = $this->getShare(); + $permissions = $share->getPermissions(); + $folder = $this->getShareNode(); + $isCreatable = ($permissions & (1 << 2)) && $folder->isCreatable(); + $file = $this->getJSONFavoritesFile($folder, $isCreatable); + $isUpdateable = ($permissions & (1 << 1)) && $file->isUpdateable(); + if ($isUpdateable) { + foreach ($categories as $cat) { + $this->favoritesService->renameCategoryInJSON($file, $cat, $newName); } - return new DataResponse('RENAMED'); + } else { + throw new NotPermittedException(); } - throw new NotFoundException(); + return new DataResponse('RENAMED'); } /** - * @PublicPage - * @param int $id - * @return DataResponse * @throws NotFoundException * @throws NotPermittedException * @throws \OCP\Files\InvalidPathException */ + #[PublicPage] public function deleteFavorite(int $id): DataResponse { $share = $this->getShare(); $permissions = $share->getPermissions(); @@ -345,13 +282,12 @@ public function deleteFavorite(int $id): DataResponse { } /** - * @PublicPage * @param array $ids - * @return DataResponse * @throws NotFoundException * @throws NotPermittedException * @throws \OCP\Files\InvalidPathException */ + #[PublicPage] public function deleteFavorites(array $ids): DataResponse { $share = $this->getShare(); $permissions = $share->getPermissions(); @@ -368,11 +304,10 @@ public function deleteFavorites(array $ids): DataResponse { } /** - * @PublicPage - * @return DataResponse * @throws NotFoundException * @throws NotPermittedException */ + #[PublicPage] public function getSharedCategories(): DataResponse { $share = $this->getShare(); $permissions = $share->getPermissions(); diff --git a/lib/Controller/PublicTracksController.php b/lib/Controller/PublicTracksController.php index a8ae719d8..f28cce4ac 100644 --- a/lib/Controller/PublicTracksController.php +++ b/lib/Controller/PublicTracksController.php @@ -157,10 +157,6 @@ public function getTrackContentByFileId(int $id): DataResponse { return new DataResponse($this->l->t('File not found'), 400); } - if ($trackFile->getType() !== \OCP\Files\FileInfo::TYPE_FILE) { - return new DataResponse($this->l->t('Bad file type'), 400); - } - $trackContent = remove_utf8_bom($trackFile->getContent()); // compute metadata if necessary // first time we get it OR the file changed @@ -194,10 +190,6 @@ public function getTrackFileContent(int $id): DataResponse { return new DataResponse($this->l->t('File not found'), 400); } - if ($trackFile->getType() !== \OCP\Files\FileInfo::TYPE_FILE) { - return new DataResponse($this->l->t('Bad file type'), 400); - } - $trackContent = remove_utf8_bom($trackFile->getContent()); // compute metadata if necessary // first time we get it OR the file changed diff --git a/lib/Controller/RoutingController.php b/lib/Controller/RoutingController.php index e4763e544..9c108177c 100644 --- a/lib/Controller/RoutingController.php +++ b/lib/Controller/RoutingController.php @@ -13,77 +13,47 @@ namespace OCA\Maps\Controller; use OCA\Maps\Service\TracksService; -use OCP\App\IAppManager; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\DataResponse; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; use OCP\IConfig; -use OCP\IDateTimeZone; -use OCP\IGroupManager; use OCP\IL10N; use OCP\IRequest; -use OCP\IServerContainer; -use OCP\IUserManager; -use OCP\Share\IManager; class RoutingController extends Controller { + private ?Folder $userfolder = null; + private string $appVersion; - private $userId; - private $userfolder; - private $config; - private $appVersion; - private $shareManager; - private $userManager; - private $groupManager; - private $dbtype; - private $dbdblquotes; - private $defaultDeviceId; - private $l; - private $dateTimeZone; - private $tracksService; - protected $appName; - - public function __construct($AppName, + public function __construct( + string $appName, IRequest $request, - IServerContainer $serverContainer, IConfig $config, - IManager $shareManager, - IAppManager $appManager, - IUserManager $userManager, - IGroupManager $groupManager, - IL10N $l, - IDateTimeZone $dateTimeZone, - TracksService $tracksService, - $UserId) { - parent::__construct($AppName, $request); - $this->dateTimeZone = $dateTimeZone; - $this->appName = $AppName; + private IL10N $l, + private TracksService $tracksService, + IRootFolder $rootFolder, + private ?string $userId, + ) { + parent::__construct($appName, $request); $this->appVersion = $config->getAppValue('maps', 'installed_version'); - $this->userId = $UserId; - $this->userManager = $userManager; - $this->groupManager = $groupManager; - $this->l = $l; - $this->dbtype = $config->getSystemValue('dbtype'); // IConfig object - $this->config = $config; - if ($UserId !== '' and $UserId !== null and $serverContainer !== null) { + if ($this->userId !== '' and $this->userId !== null) { // path of user files folder relative to DATA folder - $this->userfolder = $serverContainer->getUserFolder($UserId); + $this->userfolder = $rootFolder->getUserFolder($userId); } - $this->shareManager = $shareManager; - $this->tracksService = $tracksService; } /** - * @NoAdminRequired * @param $type * @param $coords * @param $name * @param $totDist * @param $totTime - * @return DataResponse * @throws \OCP\Files\NotFoundException * @throws \OCP\Files\NotPermittedException */ + #[NoAdminRequired] public function exportRoute($type, $coords, $name, $totDist, $totTime, $myMapId = null): DataResponse { // create /Maps directory if necessary $userFolder = $this->userfolder; @@ -93,7 +63,7 @@ public function exportRoute($type, $coords, $name, $totDist, $totTime, $myMapId } if ($userFolder->nodeExists('/Maps')) { $mapsFolder = $userFolder->get('/Maps'); - if ($mapsFolder->getType() !== \OCP\Files\FileInfo::TYPE_FOLDER) { + if (!$mapsFolder instanceof Folder) { $response = new DataResponse($this->l->t('/Maps is not a directory'), 400); return $response; } elseif (!$mapsFolder->isCreatable()) { @@ -105,15 +75,9 @@ public function exportRoute($type, $coords, $name, $totDist, $totTime, $myMapId return $response; } } else { - $folders = $userFolder->getById($myMapId); - if (!is_array($folders) or count($folders) === 0) { - $response = new DataResponse('myMaps Folder not found', 404); - return $response; - } - $mapsFolder = array_shift($folders); - if (is_null($mapsFolder)) { - $response = new DataResponse('myMaps Folder not found', 404); - return $response; + $folder = $userFolder->getFirstNodeById($myMapId); + if (!$folder instanceof Folder) { + return new DataResponse('myMaps Folder not found', 404); } } diff --git a/lib/Controller/TracksController.php b/lib/Controller/TracksController.php index 5ce31a115..0d689ccb6 100644 --- a/lib/Controller/TracksController.php +++ b/lib/Controller/TracksController.php @@ -13,69 +13,41 @@ namespace OCA\Maps\Controller; use OCA\Maps\Service\TracksService; -use OCP\App\IAppManager; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\DataResponse; -use OCP\IConfig; -use OCP\IGroupManager; +use OCP\Files\File; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; use OCP\IL10N; use OCP\IRequest; -use OCP\IServerContainer; -use OCP\IUserManager; -use OCP\Share\IManager; use function OCA\Maps\Helper\remove_utf8_bom; class TracksController extends Controller { + private ?Folder $userfolder = null; - private $userId; - private $userfolder; - private $config; - private $appVersion; - private $shareManager; - private $userManager; - private $groupManager; - private $dbtype; - private $dbdblquotes; - private $l; - private $tracksService; - protected $appName; - - public function __construct($AppName, + public function __construct( + string $appName, IRequest $request, - IServerContainer $serverContainer, - IConfig $config, - IManager $shareManager, - IAppManager $appManager, - IUserManager $userManager, - IGroupManager $groupManager, - IL10N $l, - TracksService $tracksService, - $UserId) { - parent::__construct($AppName, $request); - $this->tracksService = $tracksService; - $this->appName = $AppName; - $this->appVersion = $config->getAppValue('maps', 'installed_version'); - $this->userId = $UserId; - $this->userManager = $userManager; - $this->groupManager = $groupManager; - $this->l = $l; - $this->dbtype = $config->getSystemValue('dbtype'); - $this->config = $config; - if ($UserId !== '' and $UserId !== null and $serverContainer !== null) { - $this->userfolder = $serverContainer->getUserFolder($UserId); + private IL10N $l, + private TracksService $tracksService, + IRootFolder $rootFolder, + private ?string $userId, + ) { + parent::__construct($appName, $request); + if ($this->userId !== '' && $this->userId !== null) { + $this->userfolder = $rootFolder->getUserFolder($this->userId); } - $this->shareManager = $shareManager; } /** - * @NoAdminRequired - * @return DataResponse * @throws \OCP\Files\InvalidPathException * @throws \OCP\Files\NotFoundException */ - public function getTracks($myMapId = null): DataResponse { - if (is_null($myMapId) || $myMapId === '') { + #[NoAdminRequired] + public function getTracks(?int $myMapId = null): DataResponse { + if (is_null($myMapId)) { $tracks = $this->tracksService->getTracksFromDB($this->userId, $this->userfolder, true, false, true); } else { $folders = $this->userfolder->getById($myMapId); @@ -85,79 +57,57 @@ public function getTracks($myMapId = null): DataResponse { return new DataResponse($tracks); } - /** - * @NoAdminRequired - */ - public function getTrackContentByFileId($id) { + #[NoAdminRequired] + public function getTrackContentByFileId(int $id): DataResponse { $track = $this->tracksService->getTrackByFileIDFromDB($id, $this->userId); - $res = is_null($track) ? null : $this->userfolder->getById($track['file_id']); - if (is_array($res) and count($res) > 0) { - $trackFile = $res[0]; - if ($trackFile->getType() === \OCP\Files\FileInfo::TYPE_FILE) { - $trackContent = remove_utf8_bom($trackFile->getContent()); - // compute metadata if necessary - // first time we get it OR the file changed - if (!$track['metadata'] || $track['etag'] !== $trackFile->getEtag()) { - $metadata = $this->tracksService->generateTrackMetadata($trackFile); - $this->tracksService->editTrackInDB($track['id'], null, $metadata, $trackFile->getEtag()); - } else { - $metadata = $track['metadata']; - } - return new DataResponse([ - 'metadata' => $metadata, - 'content' => $trackContent - ]); - } else { - return new DataResponse($this->l->t('Bad file type'), 400); - } - } else { + $trackFile = is_null($track) ? null : $this->userfolder->getFirstNodeById($track['file_id']); + if (!$trackFile instanceof File) { return new DataResponse($this->l->t('File not found'), 400); } + $trackContent = remove_utf8_bom($trackFile->getContent()); + // compute metadata if necessary + // first time we get it OR the file changed + if (!$track['metadata'] || $track['etag'] !== $trackFile->getEtag()) { + $metadata = $this->tracksService->generateTrackMetadata($trackFile); + $this->tracksService->editTrackInDB($track['id'], null, $metadata, $trackFile->getEtag()); + } else { + $metadata = $track['metadata']; + } + return new DataResponse([ + 'metadata' => $metadata, + 'content' => $trackContent + ]); } /** - * @NoAdminRequired - * @param $id - * @return DataResponse * @throws \OCP\Files\InvalidPathException * @throws \OCP\Files\NotFoundException */ - public function getTrackFileContent($id): DataResponse { + #[NoAdminRequired] + public function getTrackFileContent(int $id): DataResponse { $track = $this->tracksService->getTrackFromDB($id); - $res = is_null($track) ? null : $this->userfolder->getById($track['file_id']); - if (is_array($res) and count($res) > 0) { - $trackFile = $res[0]; - if ($trackFile->getType() === \OCP\Files\FileInfo::TYPE_FILE) { - $trackContent = remove_utf8_bom($trackFile->getContent()); - // compute metadata if necessary - // first time we get it OR the file changed - if (!$track['metadata'] || $track['etag'] !== $trackFile->getEtag()) { - $metadata = $this->tracksService->generateTrackMetadata($trackFile); - $this->tracksService->editTrackInDB($track['id'], null, $metadata, $trackFile->getEtag()); - } else { - $metadata = $track['metadata']; - } - return new DataResponse([ - 'metadata' => $metadata, - 'content' => $trackContent - ]); - } else { - return new DataResponse($this->l->t('Bad file type'), 400); - } - } else { + $trackFile = is_null($track) ? null : $this->userfolder->getFirstNodeById($track['file_id']); + if (!$trackFile instanceof File) { return new DataResponse($this->l->t('File not found'), 400); } + + $trackContent = remove_utf8_bom($trackFile->getContent()); + // compute metadata if necessary + // first time we get it OR the file changed + if (!$track['metadata'] || $track['etag'] !== $trackFile->getEtag()) { + $metadata = $this->tracksService->generateTrackMetadata($trackFile); + $this->tracksService->editTrackInDB($track['id'], null, $metadata, $trackFile->getEtag()); + } else { + $metadata = $track['metadata']; + } + return new DataResponse([ + 'metadata' => $metadata, + 'content' => $trackContent + ]); } - /** - * @NoAdminRequired - * @param $id - * @param $color - * @param $metadata - * @param $etag - * @return DataResponse - */ - public function editTrack($id, $color, $metadata, $etag): DataResponse { + #[NoAdminRequired] + public function editTrack(int $id, ?string $color, ?string $metadata, ?string $etag): DataResponse { $track = $this->tracksService->getTrackFromDB($id, $this->userId); if ($track !== null) { $this->tracksService->editTrackInDB($id, $color, $metadata, $etag); @@ -167,12 +117,8 @@ public function editTrack($id, $color, $metadata, $etag): DataResponse { } } - /** - * @NoAdminRequired - * @param $id - * @return DataResponse - */ - public function deleteTrack($id): DataResponse { + #[NoAdminRequired] + public function deleteTrack(int $id): DataResponse { $track = $this->tracksService->getTrackFromDB($id, $this->userId); if ($track !== null) { $this->tracksService->deleteTrackFromDB($id); diff --git a/lib/Hooks/FileHooks.php b/lib/Hooks/FileHooks.php index edeab0479..0be737a4c 100644 --- a/lib/Hooks/FileHooks.php +++ b/lib/Hooks/FileHooks.php @@ -16,9 +16,9 @@ use OCA\Maps\Service\PhotofilesService; use OCA\Maps\Service\TracksService; use OCP\Files\File; -use OCP\Files\FileInfo; use OCP\Files\Folder; use OCP\Files\IRootFolder; +use OCP\Files\Node; use OCP\Lock\ILockingProvider; use OCP\Share\IShare; use OCP\Util; @@ -40,7 +40,7 @@ public function __construct( public function register(): void { $fileWriteCallback = function (\OCP\Files\Node $node) { //logger('maps')->debug("Hook postWrite"); - if ($node->getType() === FileInfo::TYPE_FILE && $this->isUserNode($node) && $node->getSize()) { + if ($node instanceof File && $this->isUserNode($node) && $node->getSize()) { $path = $node->getPath(); if (!$this->lockingProvider->isLocked($path, ILockingProvider::LOCK_SHARED) and !$this->lockingProvider->isLocked($path, ILockingProvider::LOCK_EXCLUSIVE) @@ -57,7 +57,7 @@ public function register(): void { $fileDeletionCallback = function (\OCP\Files\Node $node) { //logger('maps')->debug("Hook preDelete"); if ($this->isUserNode($node)) { - if ($node->getType() === FileInfo::TYPE_FOLDER) { + if ($node instanceof Folder) { $this->photofilesService->deleteByFolder($node); $this->tracksService->deleteByFolder($node); } else { @@ -71,7 +71,7 @@ public function register(): void { // this one is triggered when restoring a version of a file // and NOT when it's created so we can use it for updating coordinates in DB $this->root->listen('\OC\Files', 'postTouch', function (\OCP\Files\Node $node) { - if ($this->isUserNode($node) and $node->getType() === FileInfo::TYPE_FILE) { + if ($this->isUserNode($node) and $node instanceof File) { $this->photofilesService->updateByFile($node); // nothing to update on tracks, metadata will be regenerated when getting content if etag has changed } @@ -80,7 +80,7 @@ public function register(): void { // move file: delete then add it again in DB to be sure it's there for all users with access to target file $this->root->listen('\OC\Files', 'postRename', function (\OCP\Files\Node $source, \OCP\Files\Node $target) { if ($this->isUserNode($target)) { - if ($target->getType() === FileInfo::TYPE_FILE) { + if ($target instanceof File) { // if moved (parents are different) => update DB with access list if ($source->getParent()->getId() !== $target->getParent()->getId()) { // we renamed therefore target and source are identical @@ -88,7 +88,7 @@ public function register(): void { $this->photofilesService->addByFile($target); // tracks: nothing to do here because we use fileID } - } elseif ($target->getType() === FileInfo::TYPE_FOLDER) { + } elseif ($target instanceof Folder) { if ($source->getParent()->getId() !== $target->getParent()->getId()) { // we renamed therefore target and source have the same childs. $this->photofilesService->deleteByFolder($target); @@ -114,7 +114,7 @@ public function postShare(array $params): void { //$sourceUserId = $params['uidOwner']; $fileId = $params['fileSource']; // or itemSource $file = $this->root->getFirstNodeById($fileId); - if ($file instanceof File) { + if (!$file instanceof File) { return; } $this->photofilesService->addByFile($file); @@ -122,7 +122,7 @@ public function postShare(array $params): void { } elseif ($params['itemType'] === 'folder') { $dirId = $params['fileSource']; // or itemSource $folder = $this->root->getFirstNodeById($dirId); - if ($folder instanceof Folder) { + if (!$folder instanceof Folder) { return; } $this->photofilesService->addByFolder($folder); @@ -154,20 +154,20 @@ public function preUnShare(array $params): void { } } - public function restore($params) { + public function restore($params): void { $node = $this->getNodeForPath($params['filePath']); if ($this->isUserNode($node)) { - if ($node->getType() === FileInfo::TYPE_FOLDER) { + if ($node instanceof Folder) { $this->photofilesService->addByFolder($node); $this->tracksService->safeAddByFolder($node); - } else { + } elseif ($node instanceof File) { $this->photofilesService->addByFile($node); $this->tracksService->safeAddByFile($node); } } } - private function getNodeForPath($path) { + private function getNodeForPath($path): Node { $user = \OC::$server->getUserSession()->getUser(); $fullPath = Filesystem::normalizePath('/' . $user->getUID() . '/files/' . $path); return $this->root->get($fullPath); diff --git a/lib/Service/FavoritesService.php b/lib/Service/FavoritesService.php index 46ea10bb8..8e3fb1af7 100644 --- a/lib/Service/FavoritesService.php +++ b/lib/Service/FavoritesService.php @@ -17,17 +17,13 @@ use OC\Archive\ZIP; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Files\File; use OCP\IDBConnection; use OCP\IL10N; -use OCP\Security\ISecureRandom; use Psr\Log\LoggerInterface; class FavoritesService { - private $l10n; - private $dbconnection; - private $secureRandom; - private $currentFavorite; private $currentFavoritesList; private ?string $currentXmlTag; @@ -40,26 +36,15 @@ class FavoritesService { public function __construct( private LoggerInterface $logger, - IL10N $l10n, - ISecureRandom $secureRandom, - IDBConnection $dbconnection, + private IL10N $l10n, + private IDBConnection $dbconnection, ) { - $this->l10n = $l10n; - $this->secureRandom = $secureRandom; - $this->dbconnection = $dbconnection; - } - - private function db_quote_escape_string($str) { - return $this->dbconnection->quote($str); } /** - * @param string $userId - * @param int $pruneBefore - * @param string|null $filterCategory * @return array with favorites */ - public function getFavoritesFromDB($userId, $pruneBefore = 0, $filterCategory = null, $isDeletable = true, $isUpdateable = true, $isShareable = true) { + public function getFavoritesFromDB(string $userId, int $pruneBefore = 0, ?string $filterCategory = null, bool $isDeletable = true, bool $isUpdateable = true, bool $isShareable = true): array { $favorites = []; $qb = $this->dbconnection->getQueryBuilder(); $qb->select('id', 'name', 'date_created', 'date_modified', 'lat', 'lng', 'category', 'comment', 'extensions') @@ -109,7 +94,7 @@ public function getFavoritesFromDB($userId, $pruneBefore = 0, $filterCategory = return $favorites; } - public function getFavoriteFromDB($id, $userId = null, $category = null, $isDeletable = true, $isUpdateable = true, $isShareable = true) { + public function getFavoriteFromDB(int $id, ?string $userId = null, ?string $category = null, bool $isDeletable = true, bool $isUpdateable = true, bool $isShareable = true): ?array { $favorite = null; $qb = $this->dbconnection->getQueryBuilder(); $qb->select('id', 'name', 'date_modified', 'date_created', 'lat', 'lng', 'category', 'comment', 'extensions') @@ -160,8 +145,8 @@ public function getFavoriteFromDB($id, $userId = null, $category = null, $isDele return $favorite; } - public function addFavoriteToDB($userId, $name, $lat, $lng, $category, $comment, $extensions) { - $nowTimeStamp = (new \DateTime())->getTimestamp(); + public function addFavoriteToDB(string $userId, ?string $name, ?float $lat, ?float $lng, ?string $category, ?string $comment, ?string $extensions): int { + $nowTimeStamp = (new \DateTimeImmutable())->getTimestamp(); $qb = $this->dbconnection->getQueryBuilder(); $qb->insert('maps_favorites') ->values([ @@ -176,12 +161,11 @@ public function addFavoriteToDB($userId, $name, $lat, $lng, $category, $comment, 'extensions' => $qb->createNamedParameter($extensions, IQueryBuilder::PARAM_STR) ]); $qb->executeStatement(); - $favoriteId = $qb->getLastInsertId(); - return $favoriteId; + return $qb->getLastInsertId(); } - public function addMultipleFavoritesToDB($userId, $favoriteList) { - $nowTimeStamp = (new \DateTime())->getTimestamp(); + public function addMultipleFavoritesToDB(string $userId, array $favoriteList): void { + $nowTimeStamp = (new \DateTimeImmutable())->getTimestamp(); $qb = $this->dbconnection->getQueryBuilder(); $qb->insert('maps_favorites'); @@ -229,7 +213,7 @@ public function addMultipleFavoritesToDB($userId, $favoriteList) { } } - public function renameCategoryInDB($userId, $cat, $newName) { + public function renameCategoryInDB(string $userId, $cat, $newName): void { $qb = $this->dbconnection->getQueryBuilder(); $qb->update('maps_favorites'); $qb->set('category', $qb->createNamedParameter($newName, IQueryBuilder::PARAM_STR)); @@ -271,7 +255,7 @@ public function editFavoriteInDB($id, $name, $lat, $lng, $category, $comment, $e $qb->executeStatement(); } - public function deleteFavoriteFromDB($id) { + public function deleteFavoriteFromDB(int $id): void { $qb = $this->dbconnection->getQueryBuilder(); $qb->delete('maps_favorites') ->where( @@ -343,11 +327,10 @@ public function countFavorites($userId, $categoryList, $begin, $end) { } /** - * @param $file * @return array * @throws \Exception */ - public function getFavoritesFromJSON($file) { + public function getFavoritesFromJSON(File $file): array { $favorites = []; // Decode file content from JSON @@ -419,7 +402,7 @@ public function getFavoritesFromJSON($file) { return $favorites; } - public function getFavoriteFromJSON($file, $id) { + public function getFavoriteFromJSON(File $file, int $id) { $favorites = $this->getFavoritesFromJSON($file); if (array_key_exists($id, $favorites)) { return $favorites[$id]; diff --git a/lib/Service/PhotofilesService.php b/lib/Service/PhotofilesService.php index 1f30ed6b5..8a3dbc5bb 100644 --- a/lib/Service/PhotofilesService.php +++ b/lib/Service/PhotofilesService.php @@ -21,7 +21,7 @@ use OCA\Maps\Helper\ExifGeoData; use OCP\AppFramework\Db\DoesNotExistException; use OCP\BackgroundJob\IJobList; -use OCP\Files\FileInfo; +use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\Node; @@ -117,14 +117,14 @@ public function addByFile(Node $file) { public function addByFileIdUserId(int $fileId, string $userId): void { $userFolder = $this->root->getUserFolder($userId); $file = $userFolder->getFirstNodeById($fileId); - if ($file !== null and $this->isPhoto($file)) { + if ($file instanceof File and $this->isPhoto($file)) { $this->addPhoto($file, $userId); } } public function addByFolderIdUserId(int $folderId, string $userId): void { $folder = $this->root->getFirstNodeById($folderId); - if ($folder !== null) { + if ($folder instanceof Folder) { $photos = $this->gatherPhotoFiles($folder, true); foreach ($photos as $photo) { $this->addPhoto($photo, $userId); @@ -133,7 +133,7 @@ public function addByFolderIdUserId(int $folderId, string $userId): void { } // add all photos of a folder taking care of shared accesses - public function addByFolder($folder) { + public function addByFolder(Folder $folder): void { $photos = $this->gatherPhotoFiles($folder, true); foreach ($photos as $photo) { $this->addByFile($photo); @@ -144,7 +144,7 @@ public function updateByFile(Node $file) { $this->jobList->add(UpdatePhotoByFileJob::class, ['fileId' => $file->getId(), 'userId' => $file->getOwner()->getUID()]); } - public function updateByFileNow(Node $file) { + public function updateByFileNow(File $file): void { if ($this->isPhoto($file)) { $exif = $this->getExif($file); if (!is_null($exif)) { @@ -177,7 +177,7 @@ public function deleteByFileIdUserId(int $fileId, string $userId): void { } - public function deleteByFolder(Node $folder): void { + public function deleteByFolder(Folder $folder): void { $photos = $this->gatherPhotoFiles($folder, true); foreach ($photos as $photo) { $this->photoMapper->deleteByFileId($photo->getId()); @@ -199,10 +199,9 @@ public function deleteByFolderIdUserId($folderId, $userId) { } /** - * @param $userId * @return array */ - public function getBackgroundJobStatus($userId): array { + public function getBackgroundJobStatus(string $userId): array { $add_counter = 0; $addJobsRunning = false; @@ -250,7 +249,7 @@ private function setDirectoriesCoords(string $userId, $paths, $lats, $lngs): arr $cleanDirPath = str_replace(['../', '..\\'], '', $dirPath); if ($userFolder->nodeExists($cleanDirPath)) { $dir = $userFolder->get($cleanDirPath); - if ($dir->getType() === FileInfo::TYPE_FOLDER) { + if ($dir instanceof Folder) { $nodes = $dir->getDirectoryListing(); foreach ($nodes as $node) { if ($this->isPhoto($node) && $node->isUpdateable()) { @@ -280,7 +279,7 @@ private function setFilesCoords($userId, $paths, $lats, $lngs) { $cleanpath = str_replace(['../', '..\\'], '', $path); if ($userFolder->nodeExists($cleanpath)) { $file = $userFolder->get($cleanpath); - if ($this->isPhoto($file) && $file->isUpdateable()) { + if ($file instanceof File && $this->isPhoto($file) && $file->isUpdateable()) { $lat = (count($lats) > $i) ? $lats[$i] : $lats[0]; $lng = (count($lngs) > $i) ? $lngs[$i] : $lngs[0]; try { @@ -367,7 +366,7 @@ private function insertPhoto($photo, $userId, $exif) { $this->photosCache->clear($userId); } - private function updatePhoto($file, $exif) { + private function updatePhoto(File $file, $exif): void { $lat = is_numeric($exif->lat) && !is_nan($exif->lat) ? $exif->lat : null; $lng = is_numeric($exif->lng) && !is_nan($exif->lng) ? $exif->lng : null; $this->photoMapper->updateByFileId($file->getId(), $lat, $lng); @@ -377,13 +376,17 @@ private function normalizePath($node) { return str_replace('files', '', $node->getInternalPath()); } - public function getPhotosByFolder($userId, $path) { + public function getPhotosByFolder(string $userId, string $path): array { $userFolder = $this->root->getUserFolder($userId); $folder = $userFolder->get($path); - return $this->getPhotosListForFolder($folder); + if ($folder instanceof Folder) { + return $this->getPhotosListForFolder($folder); + } else { + return []; + } } - private function getPhotosListForFolder($folder) { + private function getPhotosListForFolder(Folder $folder): array { $FilesList = $this->gatherPhotoFiles($folder, false); $notes = []; foreach ($FilesList as $File) { @@ -395,11 +398,11 @@ private function getPhotosListForFolder($folder) { return $notes; } - private function gatherPhotoFiles($folder, $recursive) { + private function gatherPhotoFiles(Folder $folder, bool $recursive): array { $notes = []; $nodes = $folder->getDirectoryListing(); foreach ($nodes as $node) { - if ($node->getType() === FileInfo::TYPE_FOLDER and $recursive) { + if ($node instanceof Folder && $recursive) { // we don't explore external storages for which previews are disabled if ($node->isMounted()) { $options = $node->getMountPoint()->getOptions(); @@ -423,14 +426,14 @@ private function gatherPhotoFiles($folder, $recursive) { return $notes; } - private function isPhoto($file) { - if ($file->getType() !== \OCP\Files\FileInfo::TYPE_FILE) { - return false; - } - if (!in_array($file->getMimetype(), self::PHOTO_MIME_TYPES)) { + /** + * @psalm-assert $file instanceof File + */ + private function isPhoto(Node $file): bool { + if ($file instanceof File) { return false; } - return true; + return in_array($file->getMimetype(), self::PHOTO_MIME_TYPES); } /** @@ -485,7 +488,7 @@ private function resetExifCoords($file) { $file->putContent($pelJpeg->getBytes()); } - private function setExifCoords($file, $lat, $lng) { + private function setExifCoords(File $file, $lat, $lng): void { $data = new PelDataWindow($file->getContent()); $pelJpeg = new PelJpeg($data); @@ -545,7 +548,10 @@ private function setGeolocation($pelSubIfdGps, $latitudeDegreeDecimal, $longitud )); } - private function degreeDecimalToDegreeMinuteSecond($degreeDecimal) { + /** + * @return array{degree: float, minute: float, second: float} + */ + private function degreeDecimalToDegreeMinuteSecond($degreeDecimal): array { $degree = floor($degreeDecimal); $remainder = $degreeDecimal - $degree; $minute = floor($remainder * 60); diff --git a/lib/Service/TracksService.php b/lib/Service/TracksService.php index d25581ccf..21fc4a120 100644 --- a/lib/Service/TracksService.php +++ b/lib/Service/TracksService.php @@ -17,14 +17,12 @@ use OC\Files\Search\SearchQuery; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Files\File; -use OCP\Files\FileInfo; use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\Node; use OCP\Files\Search\ISearchBinaryOperator; use OCP\Files\Search\ISearchComparison; use OCP\IDBConnection; -use OCP\IL10N; use OCP\Share\IManager; use Psr\Log\LoggerInterface; @@ -36,7 +34,6 @@ class TracksService { public function __construct( private LoggerInterface $logger, - private IL10N $l10n, private IRootFolder $root, private IManager $shareManager, private IDBConnection $dbconnection, @@ -53,7 +50,7 @@ public function rescan($userId) { } } - public function addByFile(Node $file) { + public function addByFile(Node $file): void { $userFolder = $this->root->getUserFolder($file->getOwner()->getUID()); if ($this->isTrack($file)) { $this->addTrackToDB($file->getOwner()->getUID(), $file->getId(), $file); @@ -62,25 +59,24 @@ public function addByFile(Node $file) { // add the file for its owner and users that have access // check if it's already in DB before adding - public function safeAddByFile(Node $file) { + public function safeAddByFile(File $file): bool { + if (!$this->isTrack($file)) { + return false; + } + $ownerId = $file->getOwner()->getUID(); - $userFolder = $this->root->getUserFolder($ownerId); - if ($this->isTrack($file)) { - $this->safeAddTrack($file, $ownerId); - // is the file accessible to other users ? - $accesses = $this->shareManager->getAccessList($file); - foreach ($accesses['users'] as $uid) { - if ($uid !== $ownerId) { - $this->safeAddTrack($file, $uid); - } + $this->safeAddTrack($file, $ownerId); + // is the file accessible to other users ? + $accesses = $this->shareManager->getAccessList($file); + foreach ($accesses['users'] as $uid) { + if ($uid !== $ownerId) { + $this->safeAddTrack($file, $uid); } - return true; - } else { - return false; } + return true; } - public function safeAddByFileIdUserId($fileId, $userId) { + public function safeAddByFileIdUserId(int $fileId, string $userId): void { $userFolder = $this->root->getUserFolder($userId); $file = $userFolder->getFirstNodeById($fileId); if ($file === null || !$this->isTrack($file)) { @@ -89,8 +85,8 @@ public function safeAddByFileIdUserId($fileId, $userId) { $this->safeAddTrack($file, $userId); } - public function safeAddByFolderIdUserId($folderId, $userId) { - $folder = $this->root->getUserFolder($folderId); + public function safeAddByFolderIdUserId(int $folderId, string $userId): void { + $folder = $this->root->getUserFolder($userId); if ($folder === null) { return; } @@ -101,7 +97,7 @@ public function safeAddByFolderIdUserId($folderId, $userId) { } // avoid adding track if it already exists in the DB - private function safeAddTrack($track, $userId) { + private function safeAddTrack($track, string $userId): void { // filehooks are triggered several times (2 times for file creation) // so we need to be sure it's not inserted several times // by checking if it already exists in DB @@ -112,14 +108,14 @@ private function safeAddTrack($track, $userId) { } // add all tracks of a folder taking care of shared accesses - public function safeAddByFolder($folder) { + public function safeAddByFolder(Folder $folder): void { $tracks = $this->gatherTrackFiles($folder, true); foreach ($tracks as $track) { $this->safeAddByFile($track); } } - public function addByFolder(Node $folder) { + public function addByFolder(Folder $folder): void { $tracks = $this->gatherTrackFiles($folder, true); foreach ($tracks as $track) { $this->addTrackToDB($folder->getOwner()->getUID(), $track->getId(), $track); @@ -140,7 +136,7 @@ public function deleteByFile(Node $file): void { $this->deleteByFileId($file->getId()); } - public function deleteByFolder(Node $folder): void { + public function deleteByFolder(Folder $folder): void { $tracks = $this->gatherTrackFiles($folder, true); foreach ($tracks as $track) { $this->deleteByFileId($track->getId()); @@ -160,11 +156,14 @@ public function safeDeleteByFolderIdUserId(int $folderId, string $userId): void } } - private function gatherTrackFiles($folder, $recursive) { + /** + * @return list + */ + private function gatherTrackFiles(Folder $folder, bool $recursive): array { $notes = []; $nodes = $folder->getDirectoryListing(); foreach ($nodes as $node) { - if ($node->getType() === FileInfo::TYPE_FOLDER and $recursive) { + if ($node instanceof Folder && $recursive) { try { $notes = array_merge($notes, $this->gatherTrackFiles($node, $recursive)); } catch (\OCP\Files\StorageNotAvailableException|\Exception $e) { @@ -181,14 +180,11 @@ private function gatherTrackFiles($folder, $recursive) { return $notes; } - private function isTrack($file) { - if ($file->getType() !== \OCP\Files\FileInfo::TYPE_FILE) { - return false; - } - if (!in_array($file->getMimetype(), self::TRACK_MIME_TYPES)) { + private function isTrack(Node $file): bool { + if (!$file instanceof File) { return false; } - return true; + return in_array($file->getMimetype(), self::TRACK_MIME_TYPES); } private function dbRowToTrack($row, Folder $folder, $userFolder, $defaultMap, $ignoredPaths) { @@ -237,10 +233,7 @@ private function dbRowToTrack($row, Folder $folder, $userFolder, $defaultMap, $i } - /** - * @param string $userId - */ - public function getTracksFromDB($userId, $folder = null, bool $respectNomediaAndNoimage = true, bool $hideTracksOnCustomMaps = false, bool $hideTracksInMapsFolder = true) { + public function getTracksFromDB(string $userId, $folder = null, bool $respectNomediaAndNoimage = true, bool $hideTracksOnCustomMaps = false, bool $hideTracksInMapsFolder = true) { $ignoredPaths = $respectNomediaAndNoimage ? $this->getIgnoredPaths($userId, $folder, $hideTracksOnCustomMaps) : []; if ($hideTracksInMapsFolder) { $ignoredPaths[] = '/Maps'; @@ -312,7 +305,7 @@ private function getIgnoredPaths($userId, $folder = null, $hideImagesOnCustomMap return $ignoredPaths; } - public function getTrackFromDB($id, $userId = null) { + public function getTrackFromDB(int $id, ?string $userId = null) { $track = null; $qb = $this->dbconnection->getQueryBuilder(); $qb->select('id', 'file_id', 'color', 'metadata', 'etag') @@ -420,7 +413,7 @@ public function addTrackToDB($userId, $fileId, $file) { return $trackId; } - public function editTrackInDB($id, $color, $metadata, $etag): void { + public function editTrackInDB(int $id, ?string $color, ?string $metadata, ?string $etag): void { $qb = $this->dbconnection->getQueryBuilder(); $qb->update('maps_tracks'); if ($color !== null) { diff --git a/tests/Unit/Controller/ContactsControllerTest.php b/tests/Unit/Controller/ContactsControllerTest.php index cd8e6f289..580a72861 100644 --- a/tests/Unit/Controller/ContactsControllerTest.php +++ b/tests/Unit/Controller/ContactsControllerTest.php @@ -15,25 +15,29 @@ use OCA\DAV\CardDAV\CardDavBackend; use OCA\DAV\CardDAV\ContactsManager; -use OCA\DAV\Connector\Sabre\Principal; use OCA\Maps\AppInfo\Application; use OCA\Maps\Service\AddressService; -use OCP\IServerContainer; +use OCP\BackgroundJob\IJobList; +use OCP\Contacts\IManager as IContactManager; +use OCP\Files\IAppData; +use OCP\Files\IRootFolder; +use OCP\ICacheFactory; +use OCP\IGroupManager; +use OCP\IURLGenerator; +use OCP\IUserManager; +use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; class ContactsControllerTest extends \PHPUnit\Framework\TestCase { private $appName; private $request; - private $contacts; private $mapFolder; private $container; - private $config; private $app; + private IAppData&MockObject $appData; private $contactsController; - private $contactsController2; - private $utilsController; private $cdBackend; private $root; @@ -41,32 +45,30 @@ public static function setUpBeforeClass(): void { $app = new Application(); $c = $app->getContainer(); - $user = $c->getServer()->getUserManager()->get('test'); - $user2 = $c->getServer()->getUserManager()->get('test2'); - $user3 = $c->getServer()->getUserManager()->get('test3'); - $group = $c->getServer()->getGroupManager()->get('group1test'); - $group2 = $c->getServer()->getGroupManager()->get('group2test'); + $user = $c->get(IUserManager::class)->get('test'); + $user2 = $c->get(IUserManager::class)->get('test2'); + $user3 = $c->get(IUserManager::class)->get('test3'); + $group = $c->get(IGroupManager::class)->get('group1test'); + $group2 = $c->get(IGroupManager::class)->get('group2test'); // CREATE DUMMY USERS if ($user === null) { - $u1 = $c->getServer()->getUserManager()->createUser('test', 'tatotitoTUTU'); - $u1->setEMailAddress('toto@toto.net'); + $user = $c->get(IUserManager::class)->createUser('test', 'tatotitoTUTU'); + $user->setEMailAddress('toto@toto.net'); } if ($user2 === null) { - $u2 = $c->getServer()->getUserManager()->createUser('test2', 'plopinoulala000'); + $user2 = $c->get(IUserManager::class)->createUser('test2', 'plopinoulala000'); } - if ($user2 === null) { - $u3 = $c->getServer()->getUserManager()->createUser('test3', 'yeyeahPASSPASS'); + if ($user3 === null) { + $user3 = $c->get(IUserManager::class)->createUser('test3', 'yeyeahPASSPASS'); } if ($group === null) { - $c->getServer()->getGroupManager()->createGroup('group1test'); - $u1 = $c->getServer()->getUserManager()->get('test'); - $c->getServer()->getGroupManager()->get('group1test')->addUser($u1); + $c->get(IGroupManager::class)->createGroup('group1test'); + $c->get(IGroupManager::class)->get('group1test')->addUser($user); } if ($group2 === null) { - $c->getServer()->getGroupManager()->createGroup('group2test'); - $u2 = $c->getServer()->getUserManager()->get('test2'); - $c->getServer()->getGroupManager()->get('group2test')->addUser($u2); + $c->get(IGroupManager::class)->createGroup('group2test'); + $c->get(IGroupManager::class)->get('group2test')->addUser($user2); } } @@ -78,86 +80,45 @@ protected function setUp(): void { $this->request = $this->getMockBuilder('\OCP\IRequest') ->disableOriginalConstructor() ->getMock(); - $this->contacts = $this->getMockBuilder('OCP\Contacts\IManager') - ->disableOriginalConstructor() - ->getMock(); - $urlGenerator = $c->getServer()->getURLGenerator(); + $urlGenerator = $c->get(IURlGenerator::class); - $this->contactsManager = $c->query(IServerContainer::class)->getContactsManager(); - $this->cm = $c->query(ContactsManager::class); + $this->contactsManager = $c->get(IContactManager::class); + $this->cm = $c->get(ContactsManager::class); $this->cm->setupContactsProvider($this->contactsManager, 'test', $urlGenerator); $this->app = new Application(); $this->container = $this->app->getContainer(); $c = $this->container; - $this->config = $c->query(IServerContainer::class)->getConfig(); - $this->appData = $this->getMockBuilder('\OCP\Files\IAppData') - ->disableOriginalConstructor() - ->getMock(); + $this->appData = $this->createMock(\OCP\Files\IAppData::class); $this->addressService = new AddressService( - $c->query(IServerContainer::class)->getMemCacheFactory(), - $c->query(IServerContainer::class)->get(LoggerInterface::class), - $c->query(IServerContainer::class)->getJobList(), + $c->get(ICacheFactory::class), + $c->get(LoggerInterface::class), + $c->get(IJobList::class), $this->appData, - $c->query(IServerContainer::class)->query(\OCP\IDBConnection::class) + $c->get(\OCP\IDBConnection::class) ); - //$this->userPrincipalBackend = new Principal( - // $c->getServer()->getUserManager(), - // $c->getServer()->getGroupManager(), - // $c->getServer()->get(\OCP\Share\IManager::class), - // \OC::$server->getUserSession(), - // $c->query(IServerContainer::class)->getConfig(), - // \OC::$server->getAppManager() - //); - $this->userPrincipalBackend = $this->getMockBuilder('OCA\DAV\Connector\Sabre\Principal') - ->disableOriginalConstructor() - ->getMock(); + $this->userPrincipalBackend = $this->createMock(\OCA\DAV\Connector\Sabre\Principal::class); - $this->cdBackend = $c->query(IServerContainer::class)->query(CardDavBackend::class); - $this->root = $c->query(IServerContainer::class)->getRootFolder(); + $this->cdBackend = $c->get(CardDavBackend::class); + $this->root = $c->get(IRootFolder::class); $this->mapFolder = $this->createMapFolder(); $this->contactsController = new ContactsController( $this->appName, $this->request, - $c->query(IServerContainer::class)->query(\OCP\IDBConnection::class), + $c->get(\OCP\IDBConnection::class), $this->contactsManager, $this->addressService, 'test', $this->cdBackend, - $c->query(IServerContainer::class)->get(\OCP\IAvatarManager::class), + $c->get(\OCP\IAvatarManager::class), $this->root, $urlGenerator); - //$this->contactsController = $this->getMockBuilder('OCA\Maps\Controller\ContactsController') - // ->disableOriginalConstructor() - // ->getMock(); - - $this->contactsController2 = new ContactsController( - $this->appName, - $this->request, - $c->query(IServerContainer::class)->query(\OCP\IDBConnection::class), - $this->contactsManager, - $this->addressService, - 'test2', - $this->cdBackend, - $c->query(IServerContainer::class)->get(\OCP\IAvatarManager::class), - $this->root, - $urlGenerator - ); - - $this->utilsController = new UtilsController( - $this->appName, - $this->request, - $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->getAppManager(), - $this->root, - 'test' - ); } private function createMapFolder() { diff --git a/tests/Unit/Controller/DevicesApiControllerTest.php b/tests/Unit/Controller/DevicesApiControllerTest.php index bac12b4f3..5498c6bb9 100644 --- a/tests/Unit/Controller/DevicesApiControllerTest.php +++ b/tests/Unit/Controller/DevicesApiControllerTest.php @@ -27,7 +27,6 @@ class DevicesApiControllerTest extends \PHPUnit\Framework\TestCase { private $devicesApiController; private $devicesApiController2; - private $utilsController; private $root; public static function setUpBeforeClass(): void { @@ -106,15 +105,6 @@ protected function setUp(): void { 'test2' ); - $this->utilsController = new UtilsController( - $this->appName, - $this->request, - $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->getAppManager(), - $this->root, - 'test' - ); - // delete $resp = $this->devicesApiController->getDevices('1.0'); $data = $resp->getData(); diff --git a/tests/Unit/Controller/DevicesControllerTest.php b/tests/Unit/Controller/DevicesControllerTest.php index d61a7b3a8..357f35993 100644 --- a/tests/Unit/Controller/DevicesControllerTest.php +++ b/tests/Unit/Controller/DevicesControllerTest.php @@ -16,110 +16,75 @@ use OCA\Maps\DB\DeviceShareMapper; use OCA\Maps\Service\DevicesService; use OCP\Files\IRootFolder; +use OCP\IConfig; +use OCP\IGroupManager; +use OCP\IRequest; use OCP\IServerContainer; +use OCP\IUserManager; +use OCP\L10N\IFactory; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Container\ContainerInterface; class DevicesControllerTest extends \PHPUnit\Framework\TestCase { - private $appName; - private $request; - private $contacts; + private string $appName; + private IRequest&MockObject $request; + private ContainerInterface $container; + private Application $app; - private $container; - private $config; - private $app; - - private $devicesController; - private $devicesController2; - private $utilsController; - private $root; + private DevicesController $devicesController; public static function setUpBeforeClass(): void { $app = new Application(); $c = $app->getContainer(); - $user = $c->getServer()->getUserManager()->get('test'); - $user2 = $c->getServer()->getUserManager()->get('test2'); - $user3 = $c->getServer()->getUserManager()->get('test3'); - $group = $c->getServer()->getGroupManager()->get('group1test'); - $group2 = $c->getServer()->getGroupManager()->get('group2test'); + $user = $c->get(IUserManager::class)->get('test'); + $user2 = $c->get(IUserManager::class)->get('test2'); + $user3 = $c->get(IUserManager::class)->get('test3'); + $group = $c->get(IGroupManager::class)->get('group1test'); + $group2 = $c->get(IGroupManager::class)->get('group2test'); // CREATE DUMMY USERS if ($user === null) { - $u1 = $c->getServer()->getUserManager()->createUser('test', 'tatotitoTUTU'); + $u1 = $c->get(IUserManager::class)->createUser('test', 'tatotitoTUTU'); $u1->setEMailAddress('toto@toto.net'); } if ($user2 === null) { - $u2 = $c->getServer()->getUserManager()->createUser('test2', 'plopinoulala000'); + $u2 = $c->get(IUserManager::class)->createUser('test2', 'plopinoulala000'); } - if ($user2 === null) { - $u3 = $c->getServer()->getUserManager()->createUser('test3', 'yeyeahPASSPASS'); + if ($user3 === null) { + $u3 = $c->get(IUserManager::class)->createUser('test3', 'yeyeahPASSPASS'); } if ($group === null) { - $c->getServer()->getGroupManager()->createGroup('group1test'); - $u1 = $c->getServer()->getUserManager()->get('test'); - $c->getServer()->getGroupManager()->get('group1test')->addUser($u1); + $c->get(IGroupManager::class)->createGroup('group1test'); + $u1 = $c->get(IGroupManager::class)->get('test'); + $c->get(IGroupManager::class)->get('group1test')->addUser($u1); } if ($group2 === null) { - $c->getServer()->getGroupManager()->createGroup('group2test'); - $u2 = $c->getServer()->getUserManager()->get('test2'); - $c->getServer()->getGroupManager()->get('group2test')->addUser($u2); + $c->get(IGroupManager::class)->createGroup('group2test'); + $u2 = $c->get(IGroupManager::class)->get('test2'); + $c->get(IGroupManager::class)->get('group2test')->addUser($u2); } } protected function setUp(): void { $this->appName = 'maps'; - $this->request = $this->getMockBuilder('\OCP\IRequest') - ->disableOriginalConstructor() - ->getMock(); - $this->contacts = $this->getMockBuilder('OCP\Contacts\IManager') - ->disableOriginalConstructor() - ->getMock(); + $this->request = $this->createMock(\OCP\IRequest::class); $this->app = new Application(); $this->container = $this->app->getContainer(); $c = $this->container; - $this->config = $c->query(IServerContainer::class)->getConfig(); - $this->root = $c->query(IServerContainer::class)->getRootFolder(); + $this->config = $c->get(IConfig::class); + $this->root = $c->get(IRootFolder::class); $this->devicesController = new DevicesController( $this->appName, $this->request, - $c->query(IServerContainer::class), - $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->get(\OCP\Share\IManager::class), - $c->getServer()->getAppManager(), - $c->getServer()->getUserManager(), - $c->getServer()->getGroupManager(), - $c->query(IServerContainer::class)->getL10N($c->query('AppName')), - $c->query(DevicesService::class), - $c->query(DeviceShareMapper::class), - $c->query(IServerContainer::class)->get(\OCP\IDateTimeZone::class), - $c->query(IRootFolder::class), - 'test' - ); - - $this->devicesController2 = new DevicesController( - $this->appName, - $this->request, - $c->query(IServerContainer::class), - $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->get(\OCP\Share\IManager::class), - $c->getServer()->getAppManager(), - $c->getServer()->getUserManager(), - $c->getServer()->getGroupManager(), - $c->query(IServerContainer::class)->getL10N($c->query('AppName')), - $c->query(DevicesService::class), - $c->query(DeviceShareMapper::class), - $c->query(IServerContainer::class)->get(\OCP\IDateTimeZone::class), - $c->query(IRootFolder::class), - 'test2' - ); - - $this->utilsController = new UtilsController( - $this->appName, - $this->request, - $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->getAppManager(), - $this->root, + $c->get(IConfig::class), + $c->get(IFactory::class)->get('maps'), + $c->get(DevicesService::class), + $c->get(DeviceShareMapper::class), + $c->get(\OCP\IDateTimeZone::class), + $c->get(IRootFolder::class), 'test' ); diff --git a/tests/Unit/Controller/FavoritesApiControllerTest.php b/tests/Unit/Controller/FavoritesApiControllerTest.php index 939563bc8..d35c8d38f 100644 --- a/tests/Unit/Controller/FavoritesApiControllerTest.php +++ b/tests/Unit/Controller/FavoritesApiControllerTest.php @@ -28,7 +28,6 @@ class FavoritesApiControllerTest extends \PHPUnit\Framework\TestCase { private $favoritesApiController; private $favoritesApiController2; - private $utilsController; public static function setUpBeforeClass(): void { $app = new Application(); @@ -105,15 +104,6 @@ protected function setUp(): void { $c->query(FavoritesService::class), 'test2' ); - - $this->utilsController = new UtilsController( - $this->appName, - $this->request, - $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->getAppManager(), - $this->root, - 'test' - ); } public static function tearDownAfterClass(): void { diff --git a/tests/Unit/Controller/FavoritesControllerTest.php b/tests/Unit/Controller/FavoritesControllerTest.php index 7194ac275..c7165f81e 100644 --- a/tests/Unit/Controller/FavoritesControllerTest.php +++ b/tests/Unit/Controller/FavoritesControllerTest.php @@ -17,124 +17,110 @@ use OCA\Maps\AppInfo\Application; use OCA\Maps\DB\FavoriteShareMapper; use OCA\Maps\Service\FavoritesService; +use OCP\App\IAppManager; use OCP\AppFramework\Http; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; +use OCP\IConfig; +use OCP\IGroupManager; +use OCP\IRequest; use OCP\IServerContainer; +use OCP\IUserManager; +use OCP\L10N\IFactory; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Container\ContainerInterface; class FavoritesControllerTest extends \PHPUnit\Framework\TestCase { - private $appName; - private $request; - private $contacts; - - private $container; - private $config; - private $app; - - private $pageController; - private $pageController2; - private $utilsController; - private $root; - - /* @var FavoritesController */ - private $favoritesController; - - /* @var FavoritesController */ - private $favoritesController2; + private string $appName; + private IRequest&MockObject $request; + private ContainerInterface $container; + private Application $app; + private IRootFolder $root; + private FavoritesController $favoritesController; + private FavoritesController $favoritesController2; public static function setUpBeforeClass(): void { $app = new Application(); $c = $app->getContainer(); - $user = $c->getServer()->getUserManager()->get('test'); - $user2 = $c->getServer()->getUserManager()->get('test2'); - $user3 = $c->getServer()->getUserManager()->get('test3'); - $group = $c->getServer()->getGroupManager()->get('group1test'); - $group2 = $c->getServer()->getGroupManager()->get('group2test'); + $user = $c->get(IUserManager::class)->get('test'); + $user2 = $c->get(IUserManager::class)->get('test2'); + $user3 = $c->get(IUserManager::class)->get('test3'); + $group = $c->get(IGroupManager::class)->get('group1test'); + $group2 = $c->get(IGroupManager::class)->get('group2test'); // CREATE DUMMY USERS if ($user === null) { - $u1 = $c->getServer()->getUserManager()->createUser('test', 'tatotitoTUTU'); + $u1 = $c->get(IUserManager::class)->createUser('test', 'tatotitoTUTU'); $u1->setEMailAddress('toto@toto.net'); } if ($user2 === null) { - $u2 = $c->getServer()->getUserManager()->createUser('test2', 'plopinoulala000'); + $c->get(IUserManager::class)->createUser('test2', 'plopinoulala000'); } - if ($user2 === null) { - $u3 = $c->getServer()->getUserManager()->createUser('test3', 'yeyeahPASSPASS'); + if ($user3 === null) { + $c->get(IUserManager::class)->createUser('test3', 'yeyeahPASSPASS'); } if ($group === null) { - $c->getServer()->getGroupManager()->createGroup('group1test'); - $u1 = $c->getServer()->getUserManager()->get('test'); - $c->getServer()->getGroupManager()->get('group1test')->addUser($u1); + $c->get(IGroupManager::class)->createGroup('group1test'); + $u1 = $c->get(IGroupManager::class)->get('test'); + $c->get(IGroupManager::class)->get('group1test')->addUser($u1); } if ($group2 === null) { - $c->getServer()->getGroupManager()->createGroup('group2test'); - $u2 = $c->getServer()->getUserManager()->get('test2'); - $c->getServer()->getGroupManager()->get('group2test')->addUser($u2); + $c->get(IGroupManager::class)->createGroup('group2test'); + $u2 = $c->get(IGroupManager::class)->get('test2'); + $c->get(IGroupManager::class)->get('group2test')->addUser($u2); } } protected function setUp(): void { $this->appName = 'maps'; - $this->request = $this->getMockBuilder('\OCP\IRequest') - ->disableOriginalConstructor() - ->getMock(); - $this->contacts = $this->getMockBuilder('OCP\Contacts\IManager') - ->disableOriginalConstructor() - ->getMock(); + $this->request = $this->createMock(IRequest::class); $this->app = new Application(); $this->container = $this->app->getContainer(); $c = $this->container; - $this->config = $c->query(IServerContainer::class)->getConfig(); - $this->root = $c->query(IServerContainer::class)->getRootFolder(); + $this->config = $c->get(IConfig::class); + $this->root = $c->get(IRootFolder::class); $this->favoritesController = new FavoritesController( $this->appName, $this->request, - $c->query(IServerContainer::class), - $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->get(\OCP\Share\IManager::class), - $c->getServer()->getAppManager(), - $c->getServer()->getUserManager(), - $c->getServer()->getGroupManager(), - $c->query(IServerContainer::class)->getL10N($c->query('AppName')), - $c->query(FavoritesService::class), - $c->query(IServerContainer::class)->get(\OCP\IDateTimeZone::class), - $c->query(FavoriteShareMapper::class), + $c->get(IServerContainer::class), + $c->get(IConfig::class), + $c->get(\OCP\Share\IManager::class), + $c->get(IAppManager::class), + $c->get(IUserManager::class), + $c->get(IGroupManager::class), + $c->get(IFactory::class)->get($this->appName), + $c->get(FavoritesService::class), + $c->get(\OCP\IDateTimeZone::class), + $c->get(FavoriteShareMapper::class), 'test' ); $this->favoritesController2 = new FavoritesController( $this->appName, $this->request, - $c->query(IServerContainer::class), - $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->get(\OCP\Share\IManager::class), - $c->getServer()->getAppManager(), - $c->getServer()->getUserManager(), - $c->getServer()->getGroupManager(), - $c->query(IServerContainer::class)->getL10N($c->query('AppName')), - $c->query(FavoritesService::class), - $c->query(IServerContainer::class)->get(\OCP\IDateTimeZone::class), - $c->query(FavoriteShareMapper::class), + $c->get(IServerContainer::class), + $c->get(IConfig::class), + $c->get(\OCP\Share\IManager::class), + $c->get(IAppManager::class), + $c->get(IUserManager::class), + $c->get(IGroupManager::class), + $c->get(IFactory::class)->get($this->appName), + $c->get(FavoritesService::class), + $c->get(\OCP\IDateTimeZone::class), + $c->get(FavoriteShareMapper::class), 'test2' ); - $this->utilsController = new UtilsController( - $this->appName, - $this->request, - $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->getAppManager(), - $this->root, - 'test' - ); $this->mapFolder = $this->createMapFolder(); } - private function createMapFolder() { + private function createMapFolder(): Folder { $userFolder = $this->root->getUserFolder('test'); if ($userFolder->nodeExists('Map')) { - return $userFolder->get('Map')->delete(); + $userFolder->get('Map')->delete(); } return $userFolder->newFolder('Map'); } @@ -213,7 +199,8 @@ public function testAddFavorites() { $this->assertEquals(400, $status); } - public function testAddFavoritesMyMap() { + public function testAddFavoritesMyMap(): void { + $this->mapFolder = $this->createMapFolder(); $myMapId = $this->mapFolder->getId(); // correct values $resp = $this->favoritesController->addFavorite('one', 3.1, 4.2, '', null, null, $myMapId); @@ -432,7 +419,7 @@ public function testEditFavorites() { $this->assertEquals(true, $seen); } - public function testEditFavoritesMyMap() { + public function testEditFavoritesMyMap(): void { $this->mapFolder = $this->createMapFolder(); $myMapId = $this->mapFolder->getId(); // valid edition diff --git a/tests/Unit/Controller/PhotosControllerTest.php b/tests/Unit/Controller/PhotosControllerTest.php index ec491104b..e3d8d5504 100644 --- a/tests/Unit/Controller/PhotosControllerTest.php +++ b/tests/Unit/Controller/PhotosControllerTest.php @@ -119,7 +119,6 @@ protected function setUp(): void { $this->appName, $this->request, $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->getAppManager(), $this->rootFolder, 'test' ); @@ -231,7 +230,7 @@ public function testAddGetPhotos() { //Test .maps respected $this->GeoPhotosService->clearCache(); $file = $userfolder->newFile('.index.maps'); - $resp = $this->photosController->getPhotos(null, null, true); + $resp = $this->photosController->getPhotos(null, true, true); $status = $resp->getStatus(); $this->assertEquals(200, $status); $data = $resp->getData(); diff --git a/tests/Unit/Controller/PublicFavoritesApiControllerTest.php b/tests/Unit/Controller/PublicFavoritesApiControllerTest.php index 682832795..a8243b6fe 100644 --- a/tests/Unit/Controller/PublicFavoritesApiControllerTest.php +++ b/tests/Unit/Controller/PublicFavoritesApiControllerTest.php @@ -24,56 +24,49 @@ namespace OCA\Maps\Controller; -use OC; use OC\AppFramework\Http; use OCA\Maps\AppInfo\Application; -use OCA\Maps\DB\FavoriteShare; use OCA\Maps\DB\FavoriteShareMapper; use OCA\Maps\Service\FavoritesService; -use OCP\IServerContainer; +use OCP\Files\IRootFolder; +use OCP\IDBConnection; +use OCP\IRequest; +use OCP\ISession; +use OCP\L10N\IFactory; +use OCP\Security\ISecureRandom; +use OCP\Server; use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; class PublicFavoritesApiControllerTest extends TestCase { - /* @var PublicFavoritesApiController */ - private $publicFavoritesApiController; - - private $config; - - /* @var FavoritesService */ - private $favoritesService; - - /* @var FavoriteShareMapper */ - private $favoriteShareMapper; + private PublicFavoritesApiController $publicFavoritesApiController; + private FavoritesService $favoritesService; + private FavoriteShareMapper $favoriteShareMapper; protected function setUp(): void { // Begin transaction - $db = OC::$server->query(\OCP\IDBConnection::class); + $db = Server::get(IDBConnection::class); $db->beginTransaction(); $container = (new Application())->getContainer(); - $appName = $container->query('AppName'); - - $requestMock = $this->getMockBuilder('OCP\IRequest')->getMock(); - $sessionMock = $this->getMockBuilder('OCP\ISession')->getMock(); - - $this->config = $container->query(IServerContainer::class)->getConfig(); + $requestMock = $this->createMock(IRequest::class); + $sessionMock = $this->createMock(ISession::class); $this->favoritesService = new FavoritesService( - $container->query(IServerContainer::class)->get(\Psr\Log\LoggerInterface::class), - $container->query(IServerContainer::class)->getL10N($appName), - $container->query(IServerContainer::class)->getSecureRandom(), - $container->query(\OCP\IDBConnection::class) + $container->get(LoggerInterface::class), + $container->get(IFactory::class)->get('maps'), + $container->get(IDBConnection::class) ); $this->favoriteShareMapper = new FavoriteShareMapper( - $container->query(\OCP\IDBConnection::class), - $container->query(IServerContainer::class)->getSecureRandom(), - $container->query(IserverContainer::class)->getRootFolder() + $container->get(IDBConnection::class), + $container->get(ISecureRandom::class), + $container->get(IRootFolder::class), ); $this->publicFavoritesApiController = new PublicFavoritesApiController( - $appName, + 'maps', $requestMock, $sessionMock, $this->favoritesService, @@ -83,18 +76,17 @@ protected function setUp(): void { protected function tearDown(): void { // Rollback transaction - $db = OC::$server->query(\OCP\IDBConnection::class); + $db = Server::get(IDBConnection::class); $db->rollBack(); } - public function testGetFavorites() { + public function testGetFavorites(): void { $testUser = 'test099897'; $categoryName = 'test89774590'; $this->favoritesService ->addFavoriteToDB($testUser, 'Test1', 0, 0, $categoryName, '', null); - /* @var FavoriteShare */ $share = $this->favoriteShareMapper->create($testUser, $categoryName); // Mock token sent by request diff --git a/tests/Unit/Controller/TracksControllerTest.php b/tests/Unit/Controller/TracksControllerTest.php index 1d8bd3fe9..c62d1ba88 100644 --- a/tests/Unit/Controller/TracksControllerTest.php +++ b/tests/Unit/Controller/TracksControllerTest.php @@ -15,119 +15,87 @@ use OCA\Maps\AppInfo\Application; use OCA\Maps\Service\TracksService; use OCP\DB\QueryBuilder\IQueryBuilder; -use OCP\IServerContainer; +use OCP\Files\IRootFolder; +use OCP\IDBConnection; +use OCP\IGroupManager; +use OCP\IL10N; +use OCP\IRequest; +use OCP\IUserManager; use OCP\Server; +use OCP\Share\IManager as IShareManager; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; class TracksControllerTest extends \PHPUnit\Framework\TestCase { - private $appName; - private $request; - private $contacts; + private string $appName; + private IRequest&MockObject $request; + private ContainerInterface $container; + private Application $app; - private $container; - private $config; - private $app; - - private $tracksController; - private $tracksController2; - private $utilsController; - - private $tracksService; + private TracksController $tracksController; + private TracksService $tracksService; public static function setUpBeforeClass(): void { $app = new Application(); $c = $app->getContainer(); - $user = $c->getServer()->getUserManager()->get('test'); - $user2 = $c->getServer()->getUserManager()->get('test2'); - $user3 = $c->getServer()->getUserManager()->get('test3'); - $group = $c->getServer()->getGroupManager()->get('group1test'); - $group2 = $c->getServer()->getGroupManager()->get('group2test'); + $user = $c->get(IUserManager::class)->get('test'); + $user2 = $c->get(IUserManager::class)->get('test2'); + $user3 = $c->get(IUserManager::class)->get('test3'); + $group = $c->get(IGroupManager::class)->get('group1test'); + $group2 = $c->get(IGroupManager::class)->get('group2test'); // CREATE DUMMY USERS if ($user === null) { - $u1 = $c->getServer()->getUserManager()->createUser('test', 'tatotitoTUTU'); + $u1 = $c->get(IUserManager::class)->createUser('test', 'tatotitoTUTU'); $u1->setEMailAddress('toto@toto.net'); } if ($user2 === null) { - $u2 = $c->getServer()->getUserManager()->createUser('test2', 'plopinoulala000'); + $u2 = $c->get(IUserManager::class)->createUser('test2', 'plopinoulala000'); } if ($user2 === null) { - $u3 = $c->getServer()->getUserManager()->createUser('test3', 'yeyeahPASSPASS'); + $u3 = $c->get(IUserManager::class)->createUser('test3', 'yeyeahPASSPASS'); } if ($group === null) { - $c->getServer()->getGroupManager()->createGroup('group1test'); - $u1 = $c->getServer()->getUserManager()->get('test'); - $c->getServer()->getGroupManager()->get('group1test')->addUser($u1); + $c->get(IGroupManager::class)->createGroup('group1test'); + $u1 = $c->get(IUserManager::class)->get('test'); + $c->get(IGroupManager::class)->get('group1test')->addUser($u1); } if ($group2 === null) { - $c->getServer()->getGroupManager()->createGroup('group2test'); - $u2 = $c->getServer()->getUserManager()->get('test2'); - $c->getServer()->getGroupManager()->get('group2test')->addUser($u2); + $c->get(IGroupManager::class)->createGroup('group2test'); + $u2 = $c->get(IUserManager::class)->get('test2'); + $c->get(IGroupManager::class)->get('group2test')->addUser($u2); } } protected function setUp(): void { $this->appName = 'maps'; - $this->request = $this->getMockBuilder('\OCP\IRequest') - ->disableOriginalConstructor() - ->getMock(); - $this->contacts = $this->getMockBuilder('OCP\Contacts\IManager') - ->disableOriginalConstructor() - ->getMock(); + $this->request = $this->createMock(IRequest::class); $this->app = new Application(); $this->container = $this->app->getContainer(); $c = $this->container; - $this->config = $c->query(IServerContainer::class)->getConfig(); - $this->rootFolder = $c->query(IServerContainer::class)->getRootFolder(); + $this->rootFolder = $c->get(IRootFolder::class); $this->tracksService = new TracksService( - $c->query(IServerContainer::class)->get(\Psr\Log\LoggerInterface::class), - $c->query(IServerContainer::class)->getL10N($c->query('AppName')), + $c->get(LoggerInterface::class), $this->rootFolder, - $c->query(IServerContainer::class)->get(\OCP\Share\IManager::class), - $c->query(IServerContainer::class)->query(\OCP\IDBConnection::class) + $c->get(IShareManager::class), + $c->get(IDBConnection::class) ); $this->tracksController = new TracksController( $this->appName, $this->request, - $c->query(IServerContainer::class), - $c->query(IServerContainer::class)->getConfig(), - $c->query(IServerContainer::class)->get(\OCP\Share\IManager::class), - $c->getServer()->getAppManager(), - $c->getServer()->getUserManager(), - $c->getServer()->getGroupManager(), - $c->query(IServerContainer::class)->getL10N($c->query('AppName')), - $c->query(TracksService::class), + $c->get(IL10N::class), + $c->get(TracksService::class), + $c->get(IRootFolder::class), 'test', ); - $this->tracksController2 = new TracksController( - $this->appName, - $this->request, - $c->query(IServerContainer::class), - $c->query(IServerContainer::class)->getConfig(), - $c->query(IServerContainer::class)->get(\OCP\Share\IManager::class), - $c->getServer()->getAppManager(), - $c->getServer()->getUserManager(), - $c->getServer()->getGroupManager(), - $c->query(IServerContainer::class)->getL10N($c->query('AppName')), - $c->query(TracksService::class), - 'test2', - ); - - $this->utilsController = new UtilsController( - $this->appName, - $this->request, - $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->getAppManager(), - $this->rootFolder, - 'test' - ); - - $userfolder = $this->container->query(IServerContainer::class)->getUserFolder('test'); + $userfolder = $this->rootFolder->getUserFolder('test'); // delete first if ($userfolder->nodeExists('testFile1.gpx')) { @@ -147,21 +115,21 @@ protected function setUp(): void { public static function tearDownAfterClass(): void { //$app = new Application(); //$c = $app->getContainer(); - //$user = $c->getServer()->getUserManager()->get('test'); + //$user = $c->get(IUserManager::class)->get('test'); //$user->delete(); - //$user = $c->getServer()->getUserManager()->get('test2'); + //$user = $c->get(IUserManager::class)->get('test2'); //$user->delete(); - //$user = $c->getServer()->getUserManager()->get('test3'); + //$user = $c->get(IUserManager::class)->get('test3'); //$user->delete(); - //$c->getServer()->getGroupManager()->get('group1test')->delete(); - //$c->getServer()->getGroupManager()->get('group2test')->delete(); + //$c->get(IGroupManager::class)->get('group1test')->delete(); + //$c->get(IGroupManager::class)->get('group2test')->delete(); } protected function tearDown(): void { // in case there was a failure and something was not deleted $c = $this->app->getContainer(); - $userfolder = $this->container->query(IServerContainer::class)->getUserFolder('test'); + $userfolder = $this->rootFolder->getUserFolder('test'); // delete files if ($userfolder->nodeExists('testFile1.gpx')) { $file = $userfolder->get('testFile1.gpx'); @@ -177,9 +145,7 @@ protected function tearDown(): void { } public function testAddGetTracks() { - $c = $this->app->getContainer(); - - $userfolder = $this->container->query(IServerContainer::class)->getUserFolder('test'); + $userfolder = $this->rootFolder->getUserFolder('test'); $filename = 'tests/test_files/testFile1.gpx'; $content1 = file_get_contents($filename); @@ -204,8 +170,8 @@ public function testAddGetTracks() { break; } } - $this->assertEquals(true, count($data) > 0); - $this->assertEquals(true, $foundTestFile); + $this->assertTrue(count($data) > 0); + $this->assertTrue($foundTestFile); foreach ($this->tracksService->rescan('test') as $path) { //echo $path."\n"; @@ -283,5 +249,4 @@ public function testAddGetTracks() { $data = $resp->getData(); $this->assertEquals('No such track', $data); } - } From 7f5b4937e6713ebcdd5a54536c7795a0237d60fb Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Tue, 17 Feb 2026 15:38:20 +0100 Subject: [PATCH 04/15] fix: Fix various deprecations Signed-off-by: Carl Schwan --- lib/AppInfo/Application.php | 19 +-- lib/Controller/DevicesApiController.php | 103 ++++--------- lib/Controller/DevicesController.php | 6 +- lib/Controller/FavoritesApiController.php | 92 +++-------- lib/Controller/FavoritesController.php | 77 +++------- lib/Controller/PageController.php | 143 ++++++++---------- lib/Controller/PublicContactsController.php | 30 +--- lib/Controller/PublicFavoritesController.php | 6 +- lib/Controller/PublicPageController.php | 111 +++++++------- lib/Controller/PublicPhotosController.php | 6 +- lib/Controller/PublicTracksController.php | 8 +- lib/Controller/PublicUtilsController.php | 20 +-- lib/Service/DevicesService.php | 32 ++-- psalm.xml | 5 + .../Unit/Controller/PhotosControllerTest.php | 32 ++-- 15 files changed, 258 insertions(+), 432 deletions(-) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 4c76bc4b4..d381728a3 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -23,18 +23,13 @@ use OCA\Maps\Listener\CardUpdatedListener; use OCA\Maps\Listener\LoadAdditionalScriptsListener; use OCA\Maps\Listener\LoadSidebarListener; -use OCA\Maps\Service\PhotofilesService; -use OCA\Maps\Service\TracksService; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\AppFramework\Http\EmptyFeaturePolicy; use OCP\EventDispatcher\IEventDispatcher; -use OCP\Files\IRootFolder; -use OCP\Lock\ILockingProvider; use OCP\Security\FeaturePolicy\AddFeaturePolicyEvent; -use OCP\Server; class Application extends App implements IBootstrap { public const APP_ID = 'maps'; @@ -73,23 +68,13 @@ public function register(IRegistrationContext $context): void { } public function boot(IBootContext $context): void { - // ... boot logic goes here ... - $context->getAppContainer()->registerService('FileHooks', function ($c) { - return new FileHooks( - Server::get(IRootFolder::class), - Server::get(PhotofilesService::class), - Server::get(TracksService::class), - Server::get(ILockingProvider::class), - ); - }); - - $context->getAppContainer()->query('FileHooks')->register(); + $context->getAppContainer()->get(FileHooks::class)->register(); $this->registerFeaturePolicy(); } private function registerFeaturePolicy(): void { - $dispatcher = $this->getContainer()->getServer()->get(IEventDispatcher::class); + $dispatcher = $this->getContainer()->get(IEventDispatcher::class); $dispatcher->addListener(AddFeaturePolicyEvent::class, function (AddFeaturePolicyEvent $e) { $fp = new EmptyFeaturePolicy(); diff --git a/lib/Controller/DevicesApiController.php b/lib/Controller/DevicesApiController.php index f860c7155..f7e157f4d 100644 --- a/lib/Controller/DevicesApiController.php +++ b/lib/Controller/DevicesApiController.php @@ -13,73 +13,35 @@ namespace OCA\Maps\Controller; use OCA\Maps\Service\DevicesService; -use OCP\App\IAppManager; use OCP\AppFramework\ApiController; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\CORS; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\DataResponse; -use OCP\IConfig; -use OCP\IGroupManager; use OCP\IL10N; use OCP\IRequest; -use OCP\IServerContainer; -use OCP\IUserManager; -use OCP\Share\IManager; class DevicesApiController extends ApiController { - - private $userId; - private $userfolder; - private $config; - private $appVersion; - private $shareManager; - private $userManager; - private $groupManager; - private $dbtype; - private $dbdblquotes; - private $defaultDeviceId; - private $l; - private $devicesService; - protected $appName; - - public function __construct($AppName, + public function __construct( + string $appName, IRequest $request, - IServerContainer $serverContainer, - IConfig $config, - IManager $shareManager, - IAppManager $appManager, - IUserManager $userManager, - IGroupManager $groupManager, - IL10N $l, - DevicesService $devicesService, - $UserId) { - parent::__construct($AppName, $request, + private IL10N $l, + private DevicesService $devicesService, + private string $userId, + ) { + parent::__construct($appName, $request, 'PUT, POST, GET, DELETE, PATCH, OPTIONS', 'Authorization, Content-Type, Accept', 1728000); - $this->devicesService = $devicesService; - $this->appName = $AppName; - $this->appVersion = $config->getAppValue('maps', 'installed_version'); - $this->userId = $UserId; - $this->userManager = $userManager; - $this->groupManager = $groupManager; - $this->l = $l; - $this->dbtype = $config->getSystemValue('dbtype'); - // IConfig object - $this->config = $config; - if ($UserId !== '' and $UserId !== null and $serverContainer !== null) { - // path of user files folder relative to DATA folder - $this->userfolder = $serverContainer->getUserFolder($UserId); - } - $this->shareManager = $shareManager; } /** - * @NoAdminRequired - * @NoCSRFRequired - * @CORS * @param $apiversion - * @return DataResponse */ + #[NoAdminRequired] + #[NoCSRFRequired] + #[CORS] public function getDevices($apiversion): DataResponse { $now = new \DateTime(); @@ -94,23 +56,15 @@ public function getDevices($apiversion): DataResponse { ->setETag($etag); } - /** - * @NoAdminRequired - * @NoCSRFRequired - * @CORS - * @param $id - * @param int $pruneBefore - * @return DataResponse - */ - public function getDevicePoints($id, int $pruneBefore = 0): DataResponse { + #[NoAdminRequired] + #[NoCSRFRequired] + #[CORS] + public function getDevicePoints(int $id, int $pruneBefore = 0): DataResponse { $points = $this->devicesService->getDevicePointsFromDB($this->userId, $id, $pruneBefore); return new DataResponse($points); } /** - * @NoAdminRequired - * @NoCSRFRequired - * @CORS * @param $apiversion * @param $lat * @param $lng @@ -121,6 +75,9 @@ public function getDevicePoints($id, int $pruneBefore = 0): DataResponse { * @param $accuracy * @return DataResponse */ + #[NoAdminRequired] + #[NoCSRFRequired] + #[CORS] public function addDevicePoint($apiversion, $lat, $lng, $timestamp = null, $user_agent = null, $altitude = null, $battery = null, $accuracy = null): DataResponse { if (is_numeric($lat) and is_numeric($lng)) { $timestamp = $this->normalizeOptionalNumber($timestamp); @@ -147,14 +104,14 @@ public function addDevicePoint($apiversion, $lat, $lng, $timestamp = null, $user } /** - * @NoAdminRequired - * @NoCSRFRequired - * @CORS * @param $id * @param $color * @return DataResponse */ - public function editDevice($id, $color): DataResponse { + #[NoAdminRequired] + #[NoCSRFRequired] + #[CORS] + public function editDevice(int $id, $color): DataResponse { $device = $this->devicesService->getDeviceFromDB($id, $this->userId); if ($device !== null) { if (is_string($color) && strlen($color) > 0) { @@ -169,14 +126,10 @@ public function editDevice($id, $color): DataResponse { } } - /** - * @NoAdminRequired - * @NoCSRFRequired - * @CORS - * @param $id - * @return DataResponse - */ - public function deleteDevice($id): DataResponse { + #[NoAdminRequired] + #[NoCSRFRequired] + #[CORS] + public function deleteDevice(int $id): DataResponse { $device = $this->devicesService->getDeviceFromDB($id, $this->userId); if ($device !== null) { $this->devicesService->deleteDeviceFromDB($id); diff --git a/lib/Controller/DevicesController.php b/lib/Controller/DevicesController.php index 16c1b755a..9b4a6c72e 100644 --- a/lib/Controller/DevicesController.php +++ b/lib/Controller/DevicesController.php @@ -24,7 +24,7 @@ use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; -use OCP\IConfig; +use OCP\IAppConfig; use OCP\IDateTimeZone; use OCP\IL10N; use OCP\IRequest; @@ -36,7 +36,7 @@ class DevicesController extends Controller { public function __construct( string $appName, IRequest $request, - IConfig $config, + IAppConfig $appConfig, private IL10N $l, private DevicesService $devicesService, private DeviceShareMapper $deviceShareMapper, @@ -45,7 +45,7 @@ public function __construct( private ?string $userId, ) { parent::__construct($appName, $request); - $this->appVersion = $config->getAppValue('maps', 'installed_version'); + $this->appVersion = $appConfig->getValueString('maps', 'installed_version'); if ($userId !== '' && $userId !== null) { // path of user files folder relative to DATA folder $this->userFolder = $this->root->getUserFolder($userId); diff --git a/lib/Controller/FavoritesApiController.php b/lib/Controller/FavoritesApiController.php index d49718958..90927477c 100644 --- a/lib/Controller/FavoritesApiController.php +++ b/lib/Controller/FavoritesApiController.php @@ -13,73 +13,35 @@ namespace OCA\Maps\Controller; use OCA\Maps\Service\FavoritesService; -use OCP\App\IAppManager; use OCP\AppFramework\ApiController; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\CORS; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\DataResponse; -use OCP\IConfig; -use OCP\IGroupManager; use OCP\IL10N; use OCP\IRequest; -use OCP\IServerContainer; -use OCP\IUserManager; -use OCP\Share\IManager; class FavoritesApiController extends ApiController { - private $userId; - private $userfolder; - private $config; - private $appVersion; - private $shareManager; - private $userManager; - private $groupManager; - private $dbtype; - private $dbdblquotes; - private $defaultDeviceId; - private $l; - private $favoritesService; - protected $appName; - - public function __construct($AppName, + public function __construct( + string $appName, IRequest $request, - IServerContainer $serverContainer, - IConfig $config, - IManager $shareManager, - IAppManager $appManager, - IUserManager $userManager, - IGroupManager $groupManager, - IL10N $l, - FavoritesService $favoritesService, - $UserId) { - parent::__construct($AppName, $request, + private IL10N $l, + private FavoritesService $favoritesService, + private ?string $userId, + ) { + parent::__construct($appName, $request, 'PUT, POST, GET, DELETE, PATCH, OPTIONS', 'Authorization, Content-Type, Accept', 1728000); - $this->favoritesService = $favoritesService; - $this->appName = $AppName; - $this->appVersion = $config->getAppValue('maps', 'installed_version'); - $this->userId = $UserId; - $this->userManager = $userManager; - $this->groupManager = $groupManager; - $this->l = $l; - $this->dbtype = $config->getSystemValue('dbtype'); - // IConfig object - $this->config = $config; - if ($UserId !== '' and $UserId !== null and $serverContainer !== null) { - // path of user files folder relative to DATA folder - $this->userfolder = $serverContainer->getUserFolder($UserId); - } - $this->shareManager = $shareManager; } /** - * @NoAdminRequired - * @NoCSRFRequired - * @CORS * @param $apiversion - * @param int $pruneBefore - * @return DataResponse */ + #[NoAdminRequired] + #[NoCSRFRequired] + #[CORS] public function getFavorites($apiversion, int $pruneBefore = 0): DataResponse { $now = new \DateTime(); @@ -95,9 +57,6 @@ public function getFavorites($apiversion, int $pruneBefore = 0): DataResponse { } /** - * @NoAdminRequired - * @NoCSRFRequired - * @CORS * @param $apiversion * @param $name * @param $lat @@ -107,6 +66,9 @@ public function getFavorites($apiversion, int $pruneBefore = 0): DataResponse { * @param $extensions * @return DataResponse */ + #[NoAdminRequired] + #[NoCSRFRequired] + #[CORS] public function addFavorite($apiversion, $name, $lat, $lng, $category, $comment, $extensions): DataResponse { if (is_numeric($lat) && is_numeric($lng)) { $favoriteId = $this->favoritesService->addFavoriteToDB($this->userId, $name, $lat, $lng, $category, $comment, $extensions); @@ -118,19 +80,17 @@ public function addFavorite($apiversion, $name, $lat, $lng, $category, $comment, } /** - * @NoAdminRequired - * @NoCSRFRequired - * @CORS - * @param $id * @param $name * @param $lat * @param $lng * @param $category * @param $comment * @param $extensions - * @return DataResponse */ - public function editFavorite($id, $name, $lat, $lng, $category, $comment, $extensions): DataResponse { + #[NoAdminRequired] + #[NoCSRFRequired] + #[CORS] + public function editFavorite(int $id, $name, $lat, $lng, $category, $comment, $extensions): DataResponse { $favorite = $this->favoritesService->getFavoriteFromDB($id, $this->userId); if ($favorite !== null) { if (($lat === null || is_numeric($lat)) @@ -147,14 +107,10 @@ public function editFavorite($id, $name, $lat, $lng, $category, $comment, $exten } } - /** - * @NoAdminRequired - * @NoCSRFRequired - * @CORS - * @param $id - * @return DataResponse - */ - public function deleteFavorite($id): DataResponse { + #[NoAdminRequired] + #[NoCSRFRequired] + #[CORS] + public function deleteFavorite(int $id): DataResponse { $favorite = $this->favoritesService->getFavoriteFromDB($id, $this->userId); if ($favorite !== null) { $this->favoritesService->deleteFavoriteFromDB($id); diff --git a/lib/Controller/FavoritesController.php b/lib/Controller/FavoritesController.php index 016da5f66..088224365 100644 --- a/lib/Controller/FavoritesController.php +++ b/lib/Controller/FavoritesController.php @@ -16,7 +16,6 @@ use OCA\Maps\DB\FavoriteShareMapper; use OCA\Maps\Service\FavoritesService; -use OCP\App\IAppManager; use OCP\AppFramework\Controller; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; @@ -25,66 +24,38 @@ use OCP\AppFramework\Http\DataResponse; use OCP\Files\File; use OCP\Files\Folder; +use OCP\Files\IRootFolder; +use OCP\Files\Node; use OCP\Files\NotFoundException; +use OCP\IAppConfig; use OCP\IConfig; use OCP\IDateTimeZone; -use OCP\IGroupManager; use OCP\IL10N; use OCP\IRequest; -use OCP\IServerContainer; -use OCP\IUserManager; -use OCP\Share\IManager; class FavoritesController extends Controller { - - private string $userId; - private \OCP\Files\Folder $userFolder; - private IConfig $config; + private ?Folder $userFolder = null; private string $appVersion; - private IManager $shareManager; - private IUserManager $userManager; - private IGroupManager $groupManager; - private string $dbtype; - private IL10N $l; - private FavoritesService $favoritesService; - private IDateTimeZone $dateTimeZone; - private ?string $defaultFavoritsJSON; - protected $appName; - - /* @var FavoriteShareMapper */ - private $favoriteShareMapper; - - public function __construct($AppName, + private string $defaultFavoritsJSON; + + public function __construct( + string $appName, IRequest $request, - IServerContainer $serverContainer, - IConfig $config, - IManager $shareManager, - IAppManager $appManager, - IUserManager $userManager, - IGroupManager $groupManager, - IL10N $l, - FavoritesService $favoritesService, - IDateTimeZone $dateTimeZone, - FavoriteShareMapper $favoriteShareMapper, - $UserId) { - parent::__construct($AppName, $request); - $this->favoritesService = $favoritesService; - $this->dateTimeZone = $dateTimeZone; - $this->appName = $AppName; - $this->appVersion = $config->getAppValue('maps', 'installed_version'); - $this->userId = $UserId; - $this->userManager = $userManager; - $this->groupManager = $groupManager; - $this->l = $l; - $this->dbtype = $config->getSystemValue('dbtype'); + IAppConfig $appConfig, + IRootFolder $rootFolder, + private IL10N $l, + private FavoritesService $favoritesService, + private IDateTimeZone $dateTimeZone, + private FavoriteShareMapper $favoriteShareMapper, + private ?string $userId, + ) { + parent::__construct($appName, $request); + $this->appVersion = $appConfig->getValueString('maps', 'installed_version'); // IConfig object - $this->config = $config; - if ($UserId !== '' and $UserId !== null and $serverContainer !== null) { + if ($userId !== '' and $userId !== null) { // path of user files folder relative to DATA folder - $this->userFolder = $serverContainer->getUserFolder($UserId); + $this->userFolder = $rootFolder->getUserFolder($userId); } - $this->shareManager = $shareManager; - $this->favoriteShareMapper = $favoriteShareMapper; $this->defaultFavoritsJSON = json_encode([ 'type' => 'FeatureCollection', 'features' => [] @@ -92,15 +63,15 @@ public function __construct($AppName, } /** - * @param \OCP\Files\Folder $folder + * @param Folder $folder * @return mixed * @throws \OCP\Files\NotPermittedException */ - private function getJSONFavoritesFile(\OCP\Files\Folder $folder): \OCP\Files\Node { + private function getJSONFavoritesFile(Folder $folder): Node { try { $file = $folder->get('.favorites.json'); } catch (NotFoundException $e) { - $file = $folder->newFile('.favorites.json', $content = $this->defaultFavoritsJSON); + $file = $folder->newFile('.favorites.json', $this->defaultFavoritsJSON); } return $file; } @@ -110,7 +81,7 @@ private function getJSONFavoritesFile(\OCP\Files\Folder $folder): \OCP\Files\Nod */ #[NoAdminRequired] public function getFavorites(?int $myMapId = null): DataResponse { - if (is_null($myMapId) || $myMapId === '') { + if (is_null($myMapId)) { $favorites = $this->favoritesService->getFavoritesFromDB($this->userId); } else { $folder = $this->userFolder->getFirstNodeById($myMapId); diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php index d9a3d856b..d33e44a02 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -16,11 +16,14 @@ use OCA\Maps\Service\MyMapsService; use OCA\Viewer\Event\LoadViewer; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\RedirectResponse; +use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Services\IInitialState; use OCP\EventDispatcher\IEventDispatcher; -use OCP\IConfig; +use OCP\IAppConfig; use OCP\IRequest; use OCP\IURLGenerator; @@ -31,7 +34,7 @@ public function __construct( IRequest $request, private ?string $userId, private IEventDispatcher $eventDispatcher, - private IConfig $config, + private IAppConfig $appConfig, private IInitialState $initialState, private IURLGenerator $urlGenerator, ) { @@ -44,17 +47,15 @@ public function __construct( * it up in the docs or you might create a security hole. This is * basically the only required method to add this exemption, don't * add it to any other method if you don't exactly know what it does - * - * @NoAdminRequired - * @NoCSRFRequired - * @return TemplateResponse */ + #[NoAdminRequired] + #[NoCSRFRequired] public function index(): TemplateResponse { - $this->eventDispatcher->dispatch(LoadSidebar::class, new LoadSidebar()); - $this->eventDispatcher->dispatch(LoadViewer::class, new LoadViewer()); + $this->eventDispatcher->dispatchTyped(new LoadSidebar()); + $this->eventDispatcher->dispatchTyped(new LoadViewer()); $params = ['user' => $this->userId]; - $this->initialState->provideInitialState('photos', $this->config->getAppValue('photos', 'enabled', 'no') === 'yes'); + $this->initialState->provideInitialState('photos', $this->appConfig->getValueBool('photos', 'enabled')); $response = new TemplateResponse('maps', 'main', $params); $this->addCsp($response); @@ -62,10 +63,8 @@ public function index(): TemplateResponse { return $response; } - /** - * @NoAdminRequired - * @NoCSRFRequired - */ + #[NoAdminRequired] + #[NoCSRFRequired] public function indexMyMap(int $myMapId, MyMapsService $service): TemplateResponse|RedirectResponse { $map = $service->getMyMap($myMapId, $this->userId); if ($map !== null && $map['id'] !== $myMapId) { @@ -76,11 +75,11 @@ public function indexMyMap(int $myMapId, MyMapsService $service): TemplateRespon ); } - $this->eventDispatcher->dispatch(LoadSidebar::class, new LoadSidebar()); - $this->eventDispatcher->dispatch(LoadViewer::class, new LoadViewer()); + $this->eventDispatcher->dispatchTyped(new LoadSidebar()); + $this->eventDispatcher->dispatchTyped(new LoadViewer()); $params = ['user' => $this->userId]; - $this->initialState->provideInitialState('photos', $this->config->getAppValue('photos', 'enabled', 'no') === 'yes'); + $this->initialState->provideInitialState('photos', $this->appConfig->getValueBool('photos', 'enabled', 'no') === 'yes'); $response = new TemplateResponse('maps', 'main', $params); $this->addCsp($response); @@ -88,72 +87,62 @@ public function indexMyMap(int $myMapId, MyMapsService $service): TemplateRespon return $response; } - /** - * @NoAdminRequired - * @NoCSRFRequired - * @param $url - * @return TemplateResponse - */ - public function openGeoLink($url): TemplateResponse { + #[NoAdminRequired] + #[NoCSRFRequired] + public function openGeoLink(string $url): TemplateResponse { return $this->index(); } - /** - * @param $response - * @return void - */ - private function addCsp($response): void { - if (class_exists('OCP\AppFramework\Http\ContentSecurityPolicy')) { - $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); - // map tiles - $csp->addAllowedImageDomain('https://*.tile.openstreetmap.org'); - $csp->addAllowedImageDomain('https://tile.openstreetmap.org'); - $csp->addAllowedImageDomain('https://server.arcgisonline.com'); - $csp->addAllowedImageDomain('https://*.cartocdn.com'); - $csp->addAllowedImageDomain('https://*.opentopomap.org'); - $csp->addAllowedImageDomain('https://*.cartocdn.com'); - $csp->addAllowedImageDomain('https://*.ssl.fastly.net'); - $csp->addAllowedImageDomain('https://*.openstreetmap.se'); - - // default routing engine - $csp->addAllowedConnectDomain('https://*.project-osrm.org'); - $csp->addAllowedConnectDomain('https://api.mapbox.com'); - $csp->addAllowedConnectDomain('https://events.mapbox.com'); - $csp->addAllowedConnectDomain('https://graphhopper.com'); - - $csp->addAllowedChildSrcDomain('blob:'); - $csp->addAllowedWorkerSrcDomain('blob:'); - $csp->addAllowedScriptDomain('https://unpkg.com'); - // allow connections to custom routing engines - $urlKeys = [ - 'osrmBikeURL', - 'osrmCarURL', - 'osrmFootURL', - 'graphhopperURL', - 'maplibreStreetStyleURL', - 'maplibreStreetStyleAuth', - 'maplibreStreetStylePmtiles' - ]; - foreach ($urlKeys as $key) { - $url = $this->config->getAppValue('maps', $key); - if ($url !== '') { - $scheme = parse_url($url, PHP_URL_SCHEME); - $host = parse_url($url, PHP_URL_HOST); - $port = parse_url($url, PHP_URL_PORT); - $cleanUrl = $scheme . '://' . $host; - if ($port && $port !== '') { - $cleanUrl .= ':' . $port; - } - $csp->addAllowedConnectDomain($cleanUrl); + private function addCsp(Response $response): void { + $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); + // map tiles + $csp->addAllowedImageDomain('https://*.tile.openstreetmap.org'); + $csp->addAllowedImageDomain('https://tile.openstreetmap.org'); + $csp->addAllowedImageDomain('https://server.arcgisonline.com'); + $csp->addAllowedImageDomain('https://*.cartocdn.com'); + $csp->addAllowedImageDomain('https://*.opentopomap.org'); + $csp->addAllowedImageDomain('https://*.cartocdn.com'); + $csp->addAllowedImageDomain('https://*.ssl.fastly.net'); + $csp->addAllowedImageDomain('https://*.openstreetmap.se'); + + // default routing engine + $csp->addAllowedConnectDomain('https://*.project-osrm.org'); + $csp->addAllowedConnectDomain('https://api.mapbox.com'); + $csp->addAllowedConnectDomain('https://events.mapbox.com'); + $csp->addAllowedConnectDomain('https://graphhopper.com'); + + $csp->addAllowedChildSrcDomain('blob:'); + $csp->addAllowedWorkerSrcDomain('blob:'); + $csp->addAllowedScriptDomain('https://unpkg.com'); + // allow connections to custom routing engines + $urlKeys = [ + 'osrmBikeURL', + 'osrmCarURL', + 'osrmFootURL', + 'graphhopperURL', + 'maplibreStreetStyleURL', + 'maplibreStreetStyleAuth' + 'maplibreStreetStylePmtiles' + ]; + foreach ($urlKeys as $key) { + $url = $this->appConfig->getValueString('maps', $key); + if ($url !== '') { + $scheme = parse_url($url, PHP_URL_SCHEME); + $host = parse_url($url, PHP_URL_HOST); + $port = parse_url($url, PHP_URL_PORT); + $cleanUrl = $scheme . '://' . $host; + if ($port && $port !== '') { + $cleanUrl .= ':' . $port; } + $csp->addAllowedConnectDomain($cleanUrl); } - //$csp->addAllowedConnectDomain('http://192.168.0.66:5000'); - - // poi images - $csp->addAllowedImageDomain('https://nominatim.openstreetmap.org'); - // search and geocoder - $csp->addAllowedConnectDomain('https://nominatim.openstreetmap.org'); - $response->setContentSecurityPolicy($csp); } + //$csp->addAllowedConnectDomain('http://192.168.0.66:5000'); + + // poi images + $csp->addAllowedImageDomain('https://nominatim.openstreetmap.org'); + // search and geocoder + $csp->addAllowedConnectDomain('https://nominatim.openstreetmap.org'); + $response->setContentSecurityPolicy($csp); } } diff --git a/lib/Controller/PublicContactsController.php b/lib/Controller/PublicContactsController.php index 556a2a624..046b42c42 100644 --- a/lib/Controller/PublicContactsController.php +++ b/lib/Controller/PublicContactsController.php @@ -12,19 +12,15 @@ namespace OCA\Maps\Controller; -use OCA\DAV\CardDAV\CardDavBackend; use OCA\Maps\Service\AddressService; use OCP\AppFramework\Http\DataDisplayResponse; use OCP\AppFramework\Http\DataResponse; -use OCP\Contacts\IManager; use OCP\EventDispatcher\IEventDispatcher; -use OCP\Files\IRootFolder; use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\IAppConfig; use OCP\IAvatarManager; -use OCP\IConfig; -use OCP\IDBConnection; use OCP\IInitialStateService; use OCP\IRequest; use OCP\ISession; @@ -36,34 +32,20 @@ use Sabre\VObject\Reader; class PublicContactsController extends PublicPageController { - protected IManager $contactsManager; - protected AddressService $addressService; - protected CardDavBackend $cdBackend; - protected IAvatarManager $avatarManager; - protected IRootFolder $root; - public function __construct( string $appName, IRequest $request, ISession $session, IURLGenerator $urlGenerator, IEventDispatcher $eventDispatcher, - IConfig $config, + IAppConfig $appConfig, IInitialStateService $initialStateService, ShareManager $shareManager, IUserManager $userManager, - IManager $contactsManager, - IDBConnection $dbconnection, - AddressService $addressService, - CardDavBackend $cdBackend, - IAvatarManager $avatarManager, - IRootFolder $root) { - parent::__construct($appName, $request, $session, $urlGenerator, $eventDispatcher, $config, $initialStateService, $shareManager, $userManager); - $this->avatarManager = $avatarManager; - $this->contactsManager = $contactsManager; - $this->addressService = $addressService; - $this->cdBackend = $cdBackend; - $this->root = $root; + private AddressService $addressService, + private IAvatarManager $avatarManager, + ) { + parent::__construct($appName, $request, $session, $urlGenerator, $eventDispatcher, $appConfig, $initialStateService, $shareManager, $userManager); } /** diff --git a/lib/Controller/PublicFavoritesController.php b/lib/Controller/PublicFavoritesController.php index 5365f927d..fb355bde7 100644 --- a/lib/Controller/PublicFavoritesController.php +++ b/lib/Controller/PublicFavoritesController.php @@ -23,7 +23,7 @@ use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; -use OCP\IConfig; +use OCP\IAppConfig; use OCP\IInitialStateService; use OCP\IL10N; use OCP\IRequest; @@ -42,7 +42,7 @@ public function __construct( IRequest $request, ISession $session, IURLGenerator $urlGenerator, - IConfig $config, + IAppConfig $appConfig, IInitialStateService $initialStateService, IManager $shareManager, IUserManager $userManager, @@ -51,7 +51,7 @@ public function __construct( private FavoriteShareMapper $favoriteShareMapper, IEventDispatcher $eventDispatcher, ) { - parent::__construct($appName, $request, $session, $urlGenerator, $eventDispatcher, $config, $initialStateService, $shareManager, $userManager); + parent::__construct($appName, $request, $session, $urlGenerator, $eventDispatcher, $appConfig, $initialStateService, $shareManager, $userManager); $this->userManager = $userManager; $this->shareManager = $shareManager; $this->defaultFavoritsJSON = json_encode([ diff --git a/lib/Controller/PublicPageController.php b/lib/Controller/PublicPageController.php index a1d75e532..fa78b49fb 100644 --- a/lib/Controller/PublicPageController.php +++ b/lib/Controller/PublicPageController.php @@ -17,10 +17,12 @@ use OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent; use OCA\Viewer\Event\LoadViewer; use OCP\AppFramework\AuthPublicShareController; +use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\Template\PublicTemplateResponse; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Node; use OCP\Files\NotFoundException; -use OCP\IConfig; +use OCP\IAppConfig; use OCP\IInitialStateService; use OCP\IRequest; use OCP\ISession; @@ -39,7 +41,7 @@ public function __construct( ISession $session, IURLGenerator $urlGenerator, protected IEventDispatcher $eventDispatcher, - protected IConfig $config, + protected IAppConfig $appConfig, protected IInitialStateService $initialStateService, protected ShareManager $shareManager, protected IUserManager $userManager, @@ -72,7 +74,7 @@ protected function isPasswordProtected(): bool { /** * Validate the permissions of the share */ - private function validateShare(\OCP\Share\IShare $share): bool { + private function validateShare(IShare $share): bool { // If the owner is disabled no access to the link is granted $owner = $this->userManager->get($share->getShareOwner()); if ($owner === null || !$owner->isEnabled()) { @@ -89,10 +91,9 @@ private function validateShare(\OCP\Share\IShare $share): bool { } /** - * @return \OCP\Files\File|\OCP\Files\Folder * @throws NotFoundException */ - private function getShareNode() { + private function getShareNode(): Node { \OC_User::setIncognitoMode(true); // Check whether share exists @@ -117,12 +118,12 @@ private function getShareNode() { public function showShare(): PublicTemplateResponse { $shareNode = $this->getShareNode(); - $this->eventDispatcher->dispatch(LoadSidebar::class, new LoadSidebar()); - $this->eventDispatcher->dispatch(LoadViewer::class, new LoadViewer()); + $this->eventDispatcher->dispatchTyped(new LoadSidebar()); + $this->eventDispatcher->dispatchTyped(new LoadViewer()); $params = []; $params['sharingToken'] = $this->getToken(); - $this->initialStateService->provideInitialState($this->appName, 'photos', $this->config->getAppValue('photos', 'enabled', 'no') === 'yes'); + $this->initialStateService->provideInitialState($this->appName, 'photos', $this->appConfig->getValueBool('photos', 'enabled')); $response = new PublicTemplateResponse('maps', 'public/main', $params); $this->addCsp($response); @@ -192,58 +193,52 @@ protected function showIdentificationResult(bool $success = false): PublicTempla } - /** - * @param $response - * @return void - */ - private function addCsp($response): void { - if (class_exists('OCP\AppFramework\Http\ContentSecurityPolicy')) { - $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); - // map tiles - $csp->addAllowedImageDomain('https://*.tile.openstreetmap.org'); - $csp->addAllowedImageDomain('https://tile.openstreetmap.org'); - $csp->addAllowedImageDomain('https://server.arcgisonline.com'); - $csp->addAllowedImageDomain('https://*.cartocdn.com'); - $csp->addAllowedImageDomain('https://*.opentopomap.org'); - $csp->addAllowedImageDomain('https://*.cartocdn.com'); - $csp->addAllowedImageDomain('https://*.ssl.fastly.net'); - $csp->addAllowedImageDomain('https://*.openstreetmap.se'); - - // default routing engine - $csp->addAllowedConnectDomain('https://*.project-osrm.org'); - $csp->addAllowedConnectDomain('https://api.mapbox.com'); - $csp->addAllowedConnectDomain('https://events.mapbox.com'); - $csp->addAllowedConnectDomain('https://graphhopper.com'); - - $csp->addAllowedChildSrcDomain('blob:'); - $csp->addAllowedWorkerSrcDomain('blob:'); - $csp->addAllowedScriptDomain('https://unpkg.com'); - // allow connections to custom routing engines - $urlKeys = [ - 'osrmBikeURL', - 'osrmCarURL', - 'osrmFootURL', - 'graphhopperURL' - ]; - foreach ($urlKeys as $key) { - $url = $this->config->getAppValue('maps', $key); - if ($url !== '') { - $scheme = parse_url($url, PHP_URL_SCHEME); - $host = parse_url($url, PHP_URL_HOST); - $port = parse_url($url, PHP_URL_PORT); - $cleanUrl = $scheme . '://' . $host; - if ($port && $port !== '') { - $cleanUrl .= ':' . $port; - } - $csp->addAllowedConnectDomain($cleanUrl); + private function addCsp(Response $response): void { + $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); + // map tiles + $csp->addAllowedImageDomain('https://*.tile.openstreetmap.org'); + $csp->addAllowedImageDomain('https://tile.openstreetmap.org'); + $csp->addAllowedImageDomain('https://server.arcgisonline.com'); + $csp->addAllowedImageDomain('https://*.cartocdn.com'); + $csp->addAllowedImageDomain('https://*.opentopomap.org'); + $csp->addAllowedImageDomain('https://*.cartocdn.com'); + $csp->addAllowedImageDomain('https://*.ssl.fastly.net'); + $csp->addAllowedImageDomain('https://*.openstreetmap.se'); + + // default routing engine + $csp->addAllowedConnectDomain('https://*.project-osrm.org'); + $csp->addAllowedConnectDomain('https://api.mapbox.com'); + $csp->addAllowedConnectDomain('https://events.mapbox.com'); + $csp->addAllowedConnectDomain('https://graphhopper.com'); + + $csp->addAllowedChildSrcDomain('blob:'); + $csp->addAllowedWorkerSrcDomain('blob:'); + $csp->addAllowedScriptDomain('https://unpkg.com'); + // allow connections to custom routing engines + $urlKeys = [ + 'osrmBikeURL', + 'osrmCarURL', + 'osrmFootURL', + 'graphhopperURL' + ]; + foreach ($urlKeys as $key) { + $url = $this->appConfig->getValueString('maps', $key); + if ($url !== '') { + $scheme = parse_url($url, PHP_URL_SCHEME); + $host = parse_url($url, PHP_URL_HOST); + $port = parse_url($url, PHP_URL_PORT); + $cleanUrl = $scheme . '://' . $host; + if ($port && $port !== '') { + $cleanUrl .= ':' . $port; } + $csp->addAllowedConnectDomain($cleanUrl); } - - // poi images - $csp->addAllowedImageDomain('https://nominatim.openstreetmap.org'); - // search and geocoder - $csp->addAllowedConnectDomain('https://nominatim.openstreetmap.org'); - $response->setContentSecurityPolicy($csp); } + + // poi images + $csp->addAllowedImageDomain('https://nominatim.openstreetmap.org'); + // search and geocoder + $csp->addAllowedConnectDomain('https://nominatim.openstreetmap.org'); + $response->setContentSecurityPolicy($csp); } } diff --git a/lib/Controller/PublicPhotosController.php b/lib/Controller/PublicPhotosController.php index 8d4477bdf..37a801f12 100644 --- a/lib/Controller/PublicPhotosController.php +++ b/lib/Controller/PublicPhotosController.php @@ -19,7 +19,7 @@ use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; -use OCP\IConfig; +use OCP\IAppConfig; use OCP\IInitialStateService; use OCP\IRequest; @@ -37,7 +37,7 @@ public function __construct( ISession $session, IURLGenerator $urlGenerator, IEventDispatcher $eventDispatcher, - IConfig $config, + IAppConfig $appConfig, IInitialStateService $initialStateService, ShareManager $shareManager, IUserManager $userManager, @@ -45,7 +45,7 @@ public function __construct( protected PhotofilesService $photofilesService, protected IRootFolder $root, ) { - parent::__construct($appName, $request, $session, $urlGenerator, $eventDispatcher, $config, $initialStateService, $shareManager, $userManager); + parent::__construct($appName, $request, $session, $urlGenerator, $eventDispatcher, $appConfig, $initialStateService, $shareManager, $userManager); } /** diff --git a/lib/Controller/PublicTracksController.php b/lib/Controller/PublicTracksController.php index f28cce4ac..aac7f2e93 100644 --- a/lib/Controller/PublicTracksController.php +++ b/lib/Controller/PublicTracksController.php @@ -23,7 +23,7 @@ use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; -use OCP\IConfig; +use OCP\IAppConfig; use OCP\IGroupManager; use OCP\IInitialStateService; use OCP\IL10N; @@ -43,7 +43,7 @@ public function __construct( string $appName, IRequest $request, IEventDispatcher $eventDispatcher, - IConfig $config, + IAppConfig $appConfig, IInitialStateService $initialStateService, IURLGenerator $urlGenerator, ShareManager $shareManager, @@ -54,13 +54,13 @@ public function __construct( protected TracksService $tracksService, protected IRootFolder $root, ) { - parent::__construct($appName, $request, $session, $urlGenerator, $eventDispatcher, $config, $initialStateService, $shareManager, $userManager); + parent::__construct($appName, $request, $session, $urlGenerator, $eventDispatcher, $appConfig, $initialStateService, $shareManager, $userManager); } /** * Validate the permissions of the share */ - private function validateShare(\OCP\Share\IShare $share): bool { + private function validateShare(IShare $share): bool { // If the owner is disabled no access to the link is granted $owner = $this->userManager->get($share->getShareOwner()); if ($owner === null || !$owner->isEnabled()) { diff --git a/lib/Controller/PublicUtilsController.php b/lib/Controller/PublicUtilsController.php index 546287e78..eacf5b492 100644 --- a/lib/Controller/PublicUtilsController.php +++ b/lib/Controller/PublicUtilsController.php @@ -13,6 +13,7 @@ namespace OCA\Maps\Controller; +use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\DataResponse; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\GenericFileException; @@ -20,7 +21,7 @@ use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; -use OCP\IConfig; +use OCP\IAppConfig; use OCP\IInitialStateService; use OCP\IRequest; use OCP\ISession; @@ -31,23 +32,19 @@ use OCP\Share\IManager as ShareManager; class PublicUtilsController extends PublicPageController { - - protected IRootFolder $root; - public function __construct( string $appName, IRequest $request, ISession $session, IURLGenerator $urlGenerator, - IConfig $config, + IAppConfig $appConfig, IInitialStateService $initialStateService, IUserManager $userManager, ShareManager $shareManager, - IRootFolder $root, + protected IRootFolder $root, IEventDispatcher $eventDispatcher, ) { - parent::__construct($appName, $request, $session, $urlGenerator, $eventDispatcher, $config, $initialStateService, $shareManager, $userManager); - $this->root = $root; + parent::__construct($appName, $request, $session, $urlGenerator, $eventDispatcher, $appConfig, $initialStateService, $shareManager, $userManager); } /** @@ -105,7 +102,6 @@ private function getShareNode() { /** * Save options values to the DB for current user * - * @PublicPage * @param $options * @param null $myMapId * @return DataResponse @@ -114,6 +110,7 @@ private function getShareNode() { * @throws InvalidPathException * @throws NotPermittedException */ + #[PublicPage] public function saveOptionValue($options, $myMapId = null): DataResponse { $share = $this->getShare(); $permissions = $share->getPermissions(); @@ -149,13 +146,12 @@ public function saveOptionValue($options, $myMapId = null): DataResponse { /** * get options values from the config for current user * - * @PublicPage - * @return DataResponse * @throws InvalidPathException * @throws LockedException * @throws NotFoundException * @throws NotPermittedException */ + #[PublicPage] public function getOptionsValues(): DataResponse { $ov = []; @@ -199,7 +195,7 @@ public function getOptionsValues(): DataResponse { 'graphhopperURL' ]; foreach ($settingsKeys as $k) { - $v = $this->config->getAppValue('maps', $k); + $v = $this->appConfig->getValueString('maps', $k); $ov[$k] = $v; } return new DataResponse(['values' => $ov]); diff --git a/lib/Service/DevicesService.php b/lib/Service/DevicesService.php index 986c04d95..4f562d666 100644 --- a/lib/Service/DevicesService.php +++ b/lib/Service/DevicesService.php @@ -292,28 +292,16 @@ public function addPointToDB($deviceId, $lat, $lng, $ts, $altitude, $battery, $a return $pointId; } - public function addPointsToDB($deviceId, $points) { - $values = []; - foreach ($points as $p) { - $value = '(' - . $this->db_quote_escape_string($deviceId) . ', ' - . $this->db_quote_escape_string($p['lat']) . ', ' - . $this->db_quote_escape_string($p['lng']) . ', ' - . $this->db_quote_escape_string($p['date']) . ', ' - . ((isset($p['altitude']) and is_numeric($p['altitude'])) ? $this->db_quote_escape_string(floatval($p['altitude'])) : 'NULL') . ', ' - . ((isset($p['battery']) and is_numeric($p['battery'])) ? $this->db_quote_escape_string(floatval($p['battery'])) : 'NULL') . ', ' - . ((isset($p['accuracy']) and is_numeric($p['accuracy'])) ? $this->db_quote_escape_string(floatval($p['accuracy'])) : 'NULL') . ')'; - array_push($values, $value); - } - $valuesStr = implode(', ', $values); - $sql = ' - INSERT INTO *PREFIX*maps_device_points - (device_id, lat, lng, timestamp, - altitude, battery, accuracy) - VALUES ' . $valuesStr . ' ;'; - $req = $this->dbconnection->prepare($sql); - $req->execute(); - $req->closeCursor(); + public function addPointsToDB(int $deviceId, array $points): void { + try { + $this->dbconnection->beginTransaction(); + foreach ($points as $p) { + $this->addPointToDB($deviceId, $p['lat'], $p['lng'], $p['date'], $p['altitude'] ?? null, $p['battery'] ?? null, $p['accuracy'] ?? null); + } + $this->dbconnection->commit(); + } catch (Exception $ex) { + $this->dbconnection->rollBack(); + } } public function getDeviceFromDB($id, $userId) { diff --git a/psalm.xml b/psalm.xml index 8d41d878c..75bac237b 100644 --- a/psalm.xml +++ b/psalm.xml @@ -29,11 +29,16 @@ + + + + + diff --git a/tests/Unit/Controller/PhotosControllerTest.php b/tests/Unit/Controller/PhotosControllerTest.php index e3d8d5504..d73031588 100644 --- a/tests/Unit/Controller/PhotosControllerTest.php +++ b/tests/Unit/Controller/PhotosControllerTest.php @@ -16,9 +16,15 @@ use OCA\Maps\DB\GeophotoMapper; use OCA\Maps\Service\GeophotoService; use OCA\Maps\Service\PhotofilesService; +use OCP\BackgroundJob\IJobList; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Files\IRootFolder; +use OCP\ICacheFactory; +use OCP\IConfig; use OCP\IServerContainer; +use OCP\L10N\IFactory; use OCP\Server; +use Psr\Log\LoggerInterface; class PhotosControllerTest extends \PHPUnit\Framework\TestCase { private $appName; @@ -81,20 +87,20 @@ protected function setUp(): void { $this->app = new Application(); $this->container = $this->app->getContainer(); $c = $this->container; - $this->config = $c->query(IServerContainer::class)->getConfig(); + $this->config = $c->get(IConfig::class); - $this->rootFolder = $c->query(IServerContainer::class)->getRootFolder(); + $this->rootFolder = $c->get(IRootFolder::class); - $this->GeoPhotosService = $c->query(GeoPhotoService::class); + $this->GeoPhotosService = $c->get(GeoPhotoService::class); $this->photoFileService = new PhotoFilesService( - $c->query(IServerContainer::class)->get(\Psr\Log\LoggerInterface::class), - $c->query(IServerContainer::class)->getMemCacheFactory(), + $c->get(LoggerInterface::class), + $c->get(ICacheFactory::class), $this->rootFolder, - $c->query(IServerContainer::class)->getL10N($c->query('AppName')), - $c->query(GeophotoMapper::class), - $c->query(IServerContainer::class)->get(\OCP\Share\IManager::class), - $c->query(\OCP\BackgroundJob\IJobList::class) + $c->get(IFactory::class)->get($c->get('AppName')), + $c->get(GeophotoMapper::class), + $c->get(\OCP\Share\IManager::class), + $c->get(IJobList::class) ); $this->photosController = new PhotosController( @@ -109,7 +115,7 @@ protected function setUp(): void { $this->photosController2 = new PhotosController( $this->appName, $this->request, - $c->query(GeoPhotoService::class), + $c->get(GeoPhotoService::class), $this->photoFileService, $this->rootFolder, 'test2' @@ -118,12 +124,12 @@ protected function setUp(): void { $this->utilsController = new UtilsController( $this->appName, $this->request, - $c->query(IServerContainer::class)->getConfig(), + $c->get(IServerContainer::class)->getConfig(), $this->rootFolder, 'test' ); - $userfolder = $this->container->query(IServerContainer::class)->getUserFolder('test'); + $userfolder = $this->container->get(IRootFolder::class)->getUserFolder('test'); // delete files if ($userfolder->nodeExists('nc.jpg')) { $file = $userfolder->get('nc.jpg'); @@ -162,7 +168,7 @@ protected function tearDown(): void { public function testAddGetPhotos() { $c = $this->app->getContainer(); - $userfolder = $this->container->query(IServerContainer::class)->getUserFolder('test'); + $userfolder = $this->container->get(IRootFolder::class)->getUserFolder('test'); $filename = 'tests/test_files/nc.jpg'; $handle = fopen($filename, 'rb'); From d6b6b38dc3cf4e74e0f05a0f550ab05a8b113756 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Tue, 17 Feb 2026 16:07:20 +0100 Subject: [PATCH 05/15] refactor: Run rector on project Signed-off-by: Carl Schwan --- .github/workflows/psalm.yml | 2 +- composer.json | 1 + lib/AppInfo/Application.php | 8 +- lib/BackgroundJob/AddPhotoJob.php | 24 +- .../LaunchUsersInstallScanJob.php | 16 +- lib/BackgroundJob/LookupMissingGeoJob.php | 12 +- lib/BackgroundJob/UpdatePhotoByFileJob.php | 12 +- lib/BackgroundJob/UserInstallScanJob.php | 40 +- lib/Command/RegisterMimetypes.php | 15 +- lib/Command/RescanPhotos.php | 34 +- lib/Command/RescanTracks.php | 27 +- lib/Controller/ContactsController.php | 441 ++++++++------- lib/Controller/DevicesApiController.php | 35 +- lib/Controller/DevicesController.php | 114 ++-- lib/Controller/FavoritesApiController.php | 33 +- lib/Controller/FavoritesController.php | 221 ++++---- lib/Controller/MyMapsController.php | 16 +- lib/Controller/PageController.php | 25 +- lib/Controller/PhotosController.php | 33 +- lib/Controller/PublicContactsController.php | 58 +- .../PublicFavoritePageController.php | 31 +- .../PublicFavoritesApiController.php | 10 +- lib/Controller/PublicFavoritesController.php | 47 +- lib/Controller/PublicPageController.php | 11 +- lib/Controller/PublicPhotosController.php | 26 +- lib/Controller/PublicTracksController.php | 27 +- lib/Controller/PublicUtilsController.php | 28 +- lib/Controller/RoutingController.php | 42 +- lib/Controller/TracksController.php | 21 +- lib/Controller/UtilsController.php | 40 +- lib/DB/DeviceShare.php | 20 +- lib/DB/DeviceShareMapper.php | 10 +- lib/DB/FavoriteShare.php | 6 +- lib/DB/FavoriteShareMapper.php | 36 +- lib/DB/Geophoto.php | 7 +- lib/DB/GeophotoMapper.php | 7 +- lib/Helper/ExifDataInvalidException.php | 3 +- lib/Helper/ExifDataNoLocationException.php | 3 +- lib/Helper/ExifGeoData.php | 141 ++--- lib/Helper/functions.php | 9 +- lib/Hooks/FileHooks.php | 82 +-- lib/Listener/CardCreatedListener.php | 7 +- lib/Listener/CardDeletedListener.php | 7 +- lib/Listener/CardUpdatedListener.php | 7 +- .../LoadAdditionalScriptsListener.php | 3 - lib/Listener/LoadSidebarListener.php | 3 - lib/Migration/InstallScan.php | 41 +- lib/Migration/RegisterMimeType.php | 10 +- lib/Migration/UnregisterMimeType.php | 11 +- .../Version000008Date20190428142257.php | 7 +- .../Version000009Date20190625000800.php | 6 - .../Version000012Date20190703155323.php | 13 +- .../Version000012Date20190722184716.php | 13 +- .../Version000013Date20190723185417.php | 16 +- .../Version000014Date20190817184844.php | 13 +- .../Version000102Date20190901152326.php | 13 +- .../Version000106Date20191118221134.php | 6 - .../Version000107Date20200608220000.php | 13 +- .../Version000108Date20230310220000.php | 14 +- .../Version100100Date20230731135102.php | 14 +- lib/Service/AddressService.php | 100 ++-- lib/Service/DevicesService.php | 242 +++++---- lib/Service/FavoritesService.php | 329 +++++++----- lib/Service/GeophotoService.php | 115 ++-- lib/Service/MimetypeService.php | 6 +- lib/Service/MyMapsService.php | 92 ++-- lib/Service/PhotofilesService.php | 115 ++-- lib/Service/TracksService.php | 333 +++++++----- lib/Settings/AdminSettings.php | 33 +- psalm.xml | 2 + rector.php | 52 ++ tests/Integration/AppTest.php | 11 +- .../Db/FavoriteShareMapperTest.php | 39 +- .../Controller/ContactsControllerTest.php | 90 ++-- .../Controller/DevicesApiControllerTest.php | 116 ++-- .../Unit/Controller/DevicesControllerTest.php | 64 +-- .../Controller/FavoritesApiControllerTest.php | 122 ++--- .../Controller/FavoritesControllerTest.php | 140 ++--- tests/Unit/Controller/PageControllerTest.php | 39 +- .../Unit/Controller/PhotosControllerTest.php | 131 ++--- .../PublicFavoritePageControllerTest.php | 75 ++- .../PublicFavoritesApiControllerTest.php | 11 +- .../Unit/Controller/TracksControllerTest.php | 77 +-- tests/Unit/Helper/ExifGeoDataTest.php | 96 ++-- tests/psalm-baseline.xml | 63 ++- tests/stubs/oc_archive_archive.php | 10 +- tests/stubs/oc_archive_zip.php | 16 +- .../oc_files_search_searchbinaryoperator.php | 27 +- .../oc_files_search_searchcomparison.php | 29 +- tests/stubs/oc_files_search_searchquery.php | 17 +- tests/stubs/oc_hooks_emitter.php | 16 +- tests/stubs/oc_share_constants.php | 20 +- tests/stubs/oc_user_nouserexception.php | 2 + .../stubs/oca_dav_carddav_carddavbackend.php | 173 +++--- .../stubs/oca_dav_events_cardcreatedevent.php | 41 +- .../stubs/oca_dav_events_carddeletedevent.php | 41 +- .../stubs/oca_dav_events_cardupdatedevent.php | 41 +- ...ring_event_beforetemplaterenderedevent.php | 7 - vendor-bin/psalm/composer.json | 2 +- vendor-bin/psalm/composer.lock | 14 +- vendor-bin/rector/composer.json | 6 + vendor-bin/rector/composer.lock | 504 ++++++++++++++++++ 102 files changed, 3059 insertions(+), 2391 deletions(-) create mode 100644 rector.php create mode 100644 vendor-bin/rector/composer.json create mode 100644 vendor-bin/rector/composer.lock diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index d38968ea7..442e021fb 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -56,7 +56,7 @@ jobs: run: composer require --dev roave/security-advisories:dev-latest - name: Install nextcloud/ocp - run: composer require --dev nextcloud/ocp:dev-${{ steps.versions.outputs.branches-max }} --ignore-platform-reqs --with-dependencies + run: composer require --dev nextcloud/ocp:dev-${{ steps.versions.outputs.branches-min }} --ignore-platform-reqs --with-dependencies - name: Run coding standards check run: composer run psalm -- --threads=1 --monochrome --no-progress --output-format=github diff --git a/composer.json b/composer.json index a5a544a34..f2b3fbc18 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "test:integration:dev": "phpunit -c tests/phpunit.integration.xml --no-coverage --order-by=defects --stop-on-defect --fail-on-warning --stop-on-error --stop-on-failure", "test:unit": "phpunit -c tests/phpunit.unit.xml --fail-on-warning", "test:unit:dev": "phpunit -c tests/phpunit.unit.xml --no-coverage --order-by=defects --stop-on-defect --fail-on-warning --stop-on-error --stop-on-failure", + "rector": "rector && composer cs:fix", "post-install-cmd": [ "[ $COMPOSER_DEV_MODE -eq 0 ] || composer bin all install --ansi" ], diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index d381728a3..a0e323869 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -1,5 +1,7 @@ , Vinzenz Rosenkranz * @copyright Sander Brand 2014, Vinzenz Rosenkranz 2016, 2017 */ - namespace OCA\Maps\AppInfo; use OCA\DAV\Events\CardCreatedEvent; @@ -76,9 +77,10 @@ public function boot(IBootContext $context): void { private function registerFeaturePolicy(): void { $dispatcher = $this->getContainer()->get(IEventDispatcher::class); - $dispatcher->addListener(AddFeaturePolicyEvent::class, function (AddFeaturePolicyEvent $e) { + $dispatcher->addListener(AddFeaturePolicyEvent::class, function (AddFeaturePolicyEvent $e): void { $fp = new EmptyFeaturePolicy(); - $fp->addAllowedGeoLocationDomain('\'self\''); + $fp->addAllowedGeoLocationDomain("'self'"); + $e->addPolicy($fp); }); } diff --git a/lib/BackgroundJob/AddPhotoJob.php b/lib/BackgroundJob/AddPhotoJob.php index aed0cb5c6..e99d71dad 100644 --- a/lib/BackgroundJob/AddPhotoJob.php +++ b/lib/BackgroundJob/AddPhotoJob.php @@ -1,5 +1,7 @@ photofilesService = $photofilesService; $this->root = $root; $this->cacheFactory = $cacheFactory; $this->backgroundJobCache = $this->cacheFactory->createDistributed('maps:background-jobs'); } - public function run($argument) { + public function run($argument): void { $userFolder = $this->root->getUserFolder($argument['userId']); $files = $userFolder->getById($argument['photoId']); if (empty($files)) { return; } + $file = array_shift($files); $this->photofilesService->addPhotoNow($file, $argument['userId']); diff --git a/lib/BackgroundJob/LaunchUsersInstallScanJob.php b/lib/BackgroundJob/LaunchUsersInstallScanJob.php index 2edb7a293..21bb3ebc2 100644 --- a/lib/BackgroundJob/LaunchUsersInstallScanJob.php +++ b/lib/BackgroundJob/LaunchUsersInstallScanJob.php @@ -1,5 +1,7 @@ debug('Launch users install scan jobs cronjob executed'); - $this->userManager->callForSeenUsers(function (IUser $user) { + public function run($argument): void { + Server::get(LoggerInterface::class)->debug('Launch users install scan jobs cronjob executed'); + $this->userManager->callForSeenUsers(function (IUser $user): void { $this->jobList->add(UserInstallScanJob::class, ['userId' => $user->getUID()]); }); } diff --git a/lib/BackgroundJob/LookupMissingGeoJob.php b/lib/BackgroundJob/LookupMissingGeoJob.php index 4c2f171da..93827d1cc 100644 --- a/lib/BackgroundJob/LookupMissingGeoJob.php +++ b/lib/BackgroundJob/LookupMissingGeoJob.php @@ -1,5 +1,7 @@ debug('Maps address lookup cronjob executed'); + public function run($argument): void { + Server::get(LoggerInterface::class)->debug('Maps address lookup cronjob executed'); // lookup at most 200 addresses if (!$this->addressService->lookupMissingGeo(200)) { // if not all addresses where looked up successfully add a new job for next time diff --git a/lib/BackgroundJob/UpdatePhotoByFileJob.php b/lib/BackgroundJob/UpdatePhotoByFileJob.php index 436112959..030b793b5 100644 --- a/lib/BackgroundJob/UpdatePhotoByFileJob.php +++ b/lib/BackgroundJob/UpdatePhotoByFileJob.php @@ -1,5 +1,7 @@ backgroundJobCache = $this->cacheFactory->createDistributed('maps:background-jobs'); @@ -45,6 +46,7 @@ public function run($argument): void { if (!$file instanceof File) { return; } + $this->photofilesService->updateByFileNow($file); $counter = $this->backgroundJobCache->get('recentlyUpdated:' . $argument['userId']) ?? 0; diff --git a/lib/BackgroundJob/UserInstallScanJob.php b/lib/BackgroundJob/UserInstallScanJob.php index 609aae551..04e698307 100644 --- a/lib/BackgroundJob/UserInstallScanJob.php +++ b/lib/BackgroundJob/UserInstallScanJob.php @@ -1,5 +1,7 @@ config = $config; - $this->jobList = $jobList; - $this->userManager = $userManager; - $this->photofilesService = $photofilesService; - $this->tracksService = $tracksService; } - public function run($argument) { + public function run($argument): void { $userId = $argument['userId']; - \OCP\Server::get(LoggerInterface::class)->debug('Launch user install scan job for ' . $userId . ' cronjob executed'); + Server::get(LoggerInterface::class)->debug('Launch user install scan job for ' . $userId . ' cronjob executed'); // scan photos and tracks for given user $this->rescanUserPhotos($userId); $this->rescanUserTracks($userId); $this->config->setUserValue($userId, 'maps', 'installScanDone', 'yes'); } - private function rescanUserPhotos($userId) { + private function rescanUserPhotos($userId): void { //$this->output->info('======== User '.$userId.' ========'."\n"); $c = 1; foreach ($this->photofilesService->rescan($userId) as $path) { //$this->output->info('['.$c.'] Photo "'.$path.'" added'."\n"); - $c++; + ++$c; } } - private function rescanUserTracks($userId) { + private function rescanUserTracks($userId): void { //$this->output->info('======== User '.$userId.' ========'."\n"); $c = 1; foreach ($this->tracksService->rescan($userId) as $path) { //$this->output->info('['.$c.'] Track "'.$path.'" added'."\n"); - $c++; + ++$c; } } diff --git a/lib/Command/RegisterMimetypes.php b/lib/Command/RegisterMimetypes.php index dcb8434dd..20a5160c1 100644 --- a/lib/Command/RegisterMimetypes.php +++ b/lib/Command/RegisterMimetypes.php @@ -1,5 +1,7 @@ * @copyright Piotr Bator 2017 */ - namespace OCA\Maps\Command; use OCA\Maps\Service\MimetypeService; @@ -19,11 +20,10 @@ class RegisterMimetypes extends Command { - protected MimetypeService $mimetypeService; - - public function __construct(MimetypeService $mimetypeService) { + public function __construct( + protected MimetypeService $mimetypeService, + ) { parent::__construct(); - $this->mimetypeService = $mimetypeService; } /** @@ -34,11 +34,6 @@ protected function configure() { ->setDescription('Registers the maps mimetypes for existing and new files.'); } - /** - * @param InputInterface $input - * @param OutputInterface $output - * @return int - */ protected function execute(InputInterface $input, OutputInterface $output): int { $output->writeln('Register mimetypes for existing files'); $this->mimetypeService->registerForExistingFiles(); diff --git a/lib/Command/RescanPhotos.php b/lib/Command/RescanPhotos.php index 5595fb3a7..35c18408d 100644 --- a/lib/Command/RescanPhotos.php +++ b/lib/Command/RescanPhotos.php @@ -1,5 +1,7 @@ * @copyright Piotr Bator 2017 */ - namespace OCA\Maps\Command; use OCA\Maps\Service\PhotofilesService; @@ -27,20 +28,23 @@ class RescanPhotos extends Command { protected IUserManager $userManager; + protected OutputInterface $output; + protected IManager $encryptionManager; - protected PhotofilesService $photofilesService; + + protected IConfig $config; public function __construct( IUserManager $userManager, IManager $encryptionManager, - PhotofilesService $photofilesService, - IConfig $config) { + protected PhotofilesService $photofilesService, + IConfig $config, + ) { parent::__construct(); $this->userManager = $userManager; $this->encryptionManager = $encryptionManager; - $this->photofilesService = $photofilesService; $this->config = $config; } @@ -58,7 +62,7 @@ protected function configure() { ->addArgument( 'path', InputArgument::OPTIONAL, - 'Scan photos GPS exif data for the given path under user\'s files without wiping the database.' + "Scan photos GPS exif data for the given path under user's files without wiping the database." ) ->addOption( 'now', @@ -68,16 +72,12 @@ protected function configure() { ); } - /** - * @param InputInterface $input - * @param OutputInterface $output - * @return int - */ protected function execute(InputInterface $input, OutputInterface $output): int { if ($this->encryptionManager->isEnabled()) { $output->writeln('Encryption is enabled. Aborted.'); return 1; } + $this->output = $output; $userId = $input->getArgument('user_id'); $pathToScan = $input->getArgument('path'); @@ -85,8 +85,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($inBackground) { echo "Extracting coordinates from photo is performed in a BackgroundJob \n"; } + if ($userId === null) { - $this->userManager->callForSeenUsers(function (IUser $user, ?string $pathToScan = null) use ($inBackground) { + $this->userManager->callForSeenUsers(function (IUser $user, ?string $pathToScan = null) use ($inBackground): void { $this->rescanUserPhotos($user->getUID(), $inBackground, $pathToScan); }); } else { @@ -95,23 +96,22 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->rescanUserPhotos($userId, $inBackground, $pathToScan); } } + return 0; } /** - * @param string $userId - * @param bool $inBackground * @param string $pathToScan - * @return void * @throws \OCP\PreConditionNotMetException */ - private function rescanUserPhotos(string $userId, bool $inBackground = true, ?string $pathToScan = null) { + private function rescanUserPhotos(string $userId, bool $inBackground = true, ?string $pathToScan = null): void { echo '======== User ' . $userId . ' ========' . "\n"; $c = 1; foreach ($this->photofilesService->rescan($userId, $inBackground, $pathToScan) as $path) { echo '[' . $c . '] Photo "' . $path . '" added' . "\n"; - $c++; + ++$c; } + if ($pathToScan === null) { $this->config->setUserValue($userId, 'maps', 'installScanDone', 'yes'); } diff --git a/lib/Command/RescanTracks.php b/lib/Command/RescanTracks.php index 9435481d5..be208e413 100644 --- a/lib/Command/RescanTracks.php +++ b/lib/Command/RescanTracks.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Command; use OCA\Maps\Service\TracksService; @@ -26,21 +27,26 @@ class RescanTracks extends Command { protected IUserManager $userManager; + protected OutputInterface $output; + protected IManager $encryptionManager; - protected TracksService $tracksService; + + protected IConfig $config; - public function __construct(IUserManager $userManager, + public function __construct( + IUserManager $userManager, IManager $encryptionManager, - TracksService $tracksService, - IConfig $config) { + protected TracksService $tracksService, + IConfig $config, + ) { parent::__construct(); $this->userManager = $userManager; $this->encryptionManager = $encryptionManager; - $this->tracksService = $tracksService; $this->config = $config; } + protected function configure() { $this->setName('maps:scan-tracks') ->setDescription('Rescan track files') @@ -56,10 +62,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln('Encryption is enabled. Aborted.'); return 1; } + $this->output = $output; $userId = $input->getArgument('user_id'); if ($userId === null) { - $this->userManager->callForSeenUsers(function (IUser $user) { + $this->userManager->callForSeenUsers(function (IUser $user): void { $this->rescanUserTracks($user->getUID()); }); } else { @@ -68,16 +75,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->rescanUserTracks($userId); } } + return 0; } - private function rescanUserTracks($userId) { + private function rescanUserTracks(string $userId): void { echo '======== User ' . $userId . ' ========' . "\n"; $c = 1; foreach ($this->tracksService->rescan($userId) as $path) { echo '[' . $c . '] Track "' . $path . '" added' . "\n"; - $c++; + ++$c; } + $this->config->setUserValue($userId, 'maps', 'installScanDone', 'yes'); } } diff --git a/lib/Controller/ContactsController.php b/lib/Controller/ContactsController.php index ea359686d..544f9c2c4 100644 --- a/lib/Controller/ContactsController.php +++ b/lib/Controller/ContactsController.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; +use OC\User\NoUserException; use OCA\DAV\CardDAV\CardDavBackend; use OCA\Maps\Service\AddressService; use OCP\AppFramework\Controller; @@ -30,6 +32,7 @@ use OCP\IDBConnection; use OCP\IRequest; use OCP\IURLGenerator; +use Sabre\VObject\Document; use Sabre\VObject\Property\Text; use Sabre\VObject\Reader; @@ -39,36 +42,38 @@ class ContactsController extends Controller { public function __construct( string $appName, IRequest $request, - private IDBConnection $dbconnection, - private IManager $contactsManager, - private AddressService $addressService, - private string $userId, - private CardDavBackend $cdBackend, - private IAvatarManager $avatarManager, - private IRootFolder $root, - private IURLGenerator $urlGenerator, + private readonly IDBConnection $dbconnection, + private readonly IManager $contactsManager, + private readonly AddressService $addressService, + private readonly string $userId, + private readonly CardDavBackend $cdBackend, + private readonly IAvatarManager $avatarManager, + private readonly IRootFolder $root, + private readonly IURLGenerator $urlGenerator, ) { parent::__construct($appName, $request); } + /** * Converts a geo string as a float array * @param string $geo formatted as "lat;lon" * @return float[] array containing [lat;lon] */ private function geoAsFloatArray(string $geo): array { - return array_map(static fn ($value): float => floatval($value), explode(';', $geo)); + return array_map(floatval(...), explode(';', $geo)); } /** * check if geographical address is duplicated * @param list $prevGeo containing contact's previous different addresses - * @param array $geo contact's address to check + * @param float[] $geo contact's address to check * @return integer : -1 if address is new, index of duplicated address in other cases */ private function isNewAddress(array $prevGeo, array $geo): int { - if (empty($geo)) { // Address not converted to geo coords + if ($geo === []) { // Address not converted to geo coords return -1; } + $result = -1; $counter = 0; foreach ($prevGeo as $prev) { @@ -76,22 +81,25 @@ private function isNewAddress(array $prevGeo, array $geo): int { $result = $counter; break; } - $counter++; + + ++$counter; } + return $result; } /** * Get distance between two geo points. * - * @param array $coordsA GPS coordinates of first point - * @param array $coordsB GPS coordinates of second point + * @param array $coordsA GPS coordinates of first point + * @param array $coordsB GPS coordinates of second point * @return float Distance in meters between these two points */ - private function getDistance(array $coordsA, array $coordsB) { - if (empty($coordsA) || empty($coordsB)) { + private function getDistance(array $coordsA, array $coordsB): float { + if ($coordsA === [] || $coordsB === []) { return 9E999; } + $latA = deg2rad($coordsA[0]); $lonA = deg2rad($coordsA[1]); $latB = deg2rad($coordsB[0]); @@ -108,7 +116,7 @@ private function getDistance(array $coordsA, array $coordsB) { * Get contacts with coordinates * * @throws \OCP\Files\NotPermittedException - * @throws \OC\User\NoUserException + * @throws NoUserException */ #[NoAdminRequired] public function getContacts(?int $myMapId = null): DataResponse { @@ -120,16 +128,14 @@ public function getContacts(?int $myMapId = null): DataResponse { foreach ($contacts as $c) { $addressBookUri = $addressBooks[$c['addressbook-key']]->getUri(); - $uid = trim($c['UID']); + $uid = trim((string)$c['UID']); $url = $this->directUrlToContact($uid, $addressBookUri); // we don't give users, just contacts - if (strcmp($c['URI'], 'Database:' . $c['UID'] . '.vcf') !== 0 - and strcmp($uid, $userid) !== 0 - ) { + if (strcmp((string)$c['URI'], 'Database:' . $c['UID'] . '.vcf') !== 0 && strcmp($uid, $userid) !== 0) { // if the contact has a geo attibute use it - if (key_exists('GEO', $c)) { + if (array_key_exists('GEO', $c)) { $geo = $c['GEO']; if (is_string($geo) && strlen($geo) > 1) { $result[] = [ @@ -169,6 +175,7 @@ public function getContacts(?int $myMapId = null): DataResponse { } } } + // anyway try to get it from the address $card = $this->cdBackend->getContact($c['addressbook-key'], $c['URI']); if ($card) { @@ -184,10 +191,11 @@ public function getContacts(?int $myMapId = null): DataResponse { if (isset($adr->parameters()['TYPE'])) { $adrtype = $adr->parameters()['TYPE']->getValue(); } + if (strlen($geo) > 1) { if ($duplicatedIndex < 0) { - array_push($prevGeo, $geof); - array_push($prevRes, count($result)); // Add index of new item so that we can update the ADRTYPE in case of duplicate address + $prevGeo[] = $geof; + $prevRes[] = count($result); // Add index of new item so that we can update the ADRTYPE in case of duplicate address $result[] = [ 'FN' => $c['FN'] ?? $this->N2FN($c['N']) ?? '???', 'URI' => $c['URI'], @@ -205,7 +213,7 @@ public function getContacts(?int $myMapId = null): DataResponse { ]; } else { // Concatenate AddressType to the corresponding record - array_push($result[$prevRes[$duplicatedIndex]]['ADRTYPE'], $adrtype); + $result[$prevRes[$duplicatedIndex]]['ADRTYPE'][] = $adrtype; $result[$prevRes[$duplicatedIndex]]['isUpdateable'] = false; $result[$prevRes[$duplicatedIndex]]['isDeletable'] = false; $result[$prevRes[$duplicatedIndex]]['isShareable'] = false; @@ -216,71 +224,77 @@ public function getContacts(?int $myMapId = null): DataResponse { } } } + return new DataResponse($result); - } else { - //Fixme add contacts for my-maps - $result = []; - $userFolder = $this->root->getUserFolder($this->userId); - $folder = $userFolder->getFirstNodeById($myMapId); - if (!($folder instanceof Folder)) { - return new DataResponse($result); + } + + //Fixme add contacts for my-maps + $result = []; + $userFolder = $this->root->getUserFolder($this->userId); + $folder = $userFolder->getFirstNodeById($myMapId); + if (!($folder instanceof Folder)) { + return new DataResponse($result); + } + + $files = $folder->search('.vcf'); + foreach ($files as $file) { + if (!($file instanceof File)) { + continue; } - $files = $folder->search('.vcf'); - foreach ($files as $file) { - if (!($file instanceof File)) { - continue; - } - // $cards = explode("END:VCARD\r\n", $file->getContent()); - $cards = [$file->getContent()]; - foreach ($cards as $card) { - $vcard = Reader::read($card . "END:VCARD\r\n"); - if (isset($vcard->GEO)) { - $geo = $vcard->GEO; - if (is_string($geo) && strlen($geo->getValue()) > 1) { - $result[] = $this->vCardToArray($file, $vcard, $geo->getValue()); - } elseif (is_countable($geo) && count($geo) > 0 && is_iterable($geo)) { - $prevGeo = ''; - foreach ($geo as $g) { - if (strcmp($prevGeo, $g->getValue()) != 0) { - $prevGeo = $g->getValue(); - if (strlen($g->getValue()) > 1) { - $result[] = $this->vCardToArray($file, $vcard, $g->getValue()); - } + + // $cards = explode("END:VCARD\r\n", $file->getContent()); + $cards = [$file->getContent()]; + foreach ($cards as $card) { + $vcard = Reader::read($card . "END:VCARD\r\n"); + if (isset($vcard->GEO)) { + $geo = $vcard->GEO; + if (is_string($geo) && strlen($geo->getValue()) > 1) { + $result[] = $this->vCardToArray($file, $vcard, $geo->getValue()); + } elseif (is_countable($geo) && count($geo) > 0 && is_iterable($geo)) { + $prevGeo = ''; + foreach ($geo as $g) { + if (strcmp((string)$prevGeo, (string)$g->getValue()) !== 0) { + $prevGeo = $g->getValue(); + if (strlen((string)$g->getValue()) > 1) { + $result[] = $this->vCardToArray($file, $vcard, $g->getValue()); } } } } - if (isset($vcard->ADR) && count($vcard->ADR) > 0) { - $prevGeo = []; - $prevRes = []; - foreach ($vcard->ADR as $adr) { - $geo = $this->addressService->addressToGeo($adr->getValue(), $file->getId()); - $geof = $this->geoAsFloatArray($geo); - $duplicatedIndex = $this->isNewAddress($prevGeo, $geof); - //var_dump($adr->parameters()['TYPE']->getValue()); - $adrtype = ''; - if (isset($adr->parameters()['TYPE'])) { - $adrtype = $adr->parameters()['TYPE']->getValue(); - } - if (strlen($geo) > 1) { - if ($duplicatedIndex < 0) { - array_push($prevGeo, $geof); - array_push($prevRes, count($result)); // Add index of new item so that we can update the ADRTYPE in case of duplicate address - $result[] = $this->vCardToArray($file, $vcard, $geo, $adrtype, $adr->getValue(), $file->getId()); - } else { - // Concatenate AddressType to the corresponding record - array_push($result[$prevRes[$duplicatedIndex]]['ADRTYPE'], $adrtype); - $result[$prevRes[$duplicatedIndex]]['isUpdateable'] = false; - $result[$prevRes[$duplicatedIndex]]['isDeletable'] = false; - $result[$prevRes[$duplicatedIndex]]['isShareable'] = false; - } + } + + if (isset($vcard->ADR) && count($vcard->ADR) > 0) { + $prevGeo = []; + $prevRes = []; + foreach ($vcard->ADR as $adr) { + $geo = $this->addressService->addressToGeo($adr->getValue(), $file->getId()); + $geof = $this->geoAsFloatArray($geo); + $duplicatedIndex = $this->isNewAddress($prevGeo, $geof); + //var_dump($adr->parameters()['TYPE']->getValue()); + $adrtype = ''; + if (isset($adr->parameters()['TYPE'])) { + $adrtype = $adr->parameters()['TYPE']->getValue(); + } + + if (strlen($geo) > 1) { + if ($duplicatedIndex < 0) { + $prevGeo[] = $geof; + $prevRes[] = count($result); // Add index of new item so that we can update the ADRTYPE in case of duplicate address + $result[] = $this->vCardToArray($file, $vcard, $geo, $adrtype, $adr->getValue(), $file->getId()); + } else { + // Concatenate AddressType to the corresponding record + $result[$prevRes[$duplicatedIndex]]['ADRTYPE'][] = $adrtype; + $result[$prevRes[$duplicatedIndex]]['isUpdateable'] = false; + $result[$prevRes[$duplicatedIndex]]['isDeletable'] = false; + $result[$prevRes[$duplicatedIndex]]['isShareable'] = false; } } } } } - return new DataResponse($result); } + + return new DataResponse($result); } private function directUrlToContact(string $contactUid, string $addressBookUri): string { @@ -292,16 +306,11 @@ private function directUrlToContact(string $contactUid, string $addressBookUri): } /** - * @param \Sabre\VObject\Document $vcard - * @param string $geo - * @param string|null $adrtype - * @param string|null $adr - * @param int|null $fileId - * @return array * @throws NotFoundException * @throws \OCP\Files\InvalidPathException + * @return array */ - private function vCardToArray(Node $file, \Sabre\VObject\Document $vcard, string $geo, ?string $adrtype = null, ?string $adr = null, ?int $fileId = null): array { + private function vCardToArray(Node $file, Document $vcard, string $geo, ?string $adrtype = null, ?string $adr = null, ?int $fileId = null): array { $FNArray = $vcard->FN ? $vcard->FN->getJsonValue() : []; $fn = array_shift($FNArray); $NArray = $vcard->N ? $vcard->N->getJsonValue() : []; @@ -314,15 +323,12 @@ private function vCardToArray(Node $file, \Sabre\VObject\Document $vcard, string } } + $UIDArray = $vcard->UID->getJsonValue(); $uid = array_shift($UIDArray); $groups = $vcard->CATEGORIES; - if (!is_null($groups)) { - $groups = $groups->getValue(); - } else { - $groups = ''; - } - $result = [ + $groups = is_null($groups) ? '' : $groups->getValue(); + return [ 'FN' => $fn ?? $n ?? '???', 'UID' => $uid, 'HAS_PHOTO' => (isset($vcard->PHOTO) && $vcard->PHOTO !== null), @@ -335,24 +341,19 @@ private function vCardToArray(Node $file, \Sabre\VObject\Document $vcard, string 'isDeletable' => $file->isDeletable(), 'isUpdateable' => $file->isUpdateable(), ]; - return $result; } - /** - * @param string $n - * @return string|null - */ private function N2FN(string $n): ?string { - if ($n) { + if ($n !== '' && $n !== '0') { $spl = explode($n, ';'); if (count($spl) >= 4) { return $spl[3] . ' ' . $spl[1] . ' ' . $spl[0]; - } else { - return null; } - } else { + return null; } + + return null; } /** @@ -366,11 +367,9 @@ public function searchContacts(string $query = ''): DataResponse { $result = []; $userid = trim($this->userId); foreach ($contacts as $c) { - $uid = trim($c['UID']); + $uid = trim((string)$c['UID']); // we don't give users, just contacts - if (strcmp($c['URI'], 'Database:' . $c['UID'] . '.vcf') !== 0 - and strcmp($uid, $userid) !== 0 - ) { + if (strcmp((string)$c['URI'], 'Database:' . $c['UID'] . '.vcf') !== 0 && strcmp($uid, $userid) !== 0) { $addressBookUri = $addressBooks[$c['addressbook-key']]->getUri(); $result[] = [ 'FN' => $c['FN'] ?? $this->N2FN($c['N']) ?? '???', @@ -384,145 +383,136 @@ public function searchContacts(string $query = ''): DataResponse { ]; } } + return new DataResponse($result); } /** * @throws \OCP\DB\Exception * @throws \OCP\Files\NotPermittedException - * @throws \OC\User\NoUserException + * @throws NoUserException */ #[NoAdminRequired] - public function placeContact( - int $bookid, - string $uri, - string $uid, - ?float $lat, - ?float $lng, - string $attraction = '', - string $house_number = '', - string $road = '', - string $postcode = '', - string $city = '', - string $state = '', - string $country = '', - string $type = '', - ?string $address_string = null, - ?int $fileId = null, - ?int $myMapId = null): DataResponse { + public function placeContact(int $bookid, string $uri, string $uid, ?float $lat, ?float $lng, string $attraction = '', string $house_number = '', string $road = '', string $postcode = '', string $city = '', string $state = '', string $country = '', string $type = '', ?string $address_string = null, ?int $fileId = null, ?int $myMapId = null): DataResponse { if (is_null($myMapId)) { // do not edit 'user' contact even myself - if (strcmp($uri, 'Database:' . $uid . '.vcf') === 0 - or strcmp($uid, $this->userId) === 0 - ) { - return new DataResponse('Can\'t edit users', 400); - } else { - // check addressbook permissions - if (!$this->addressBookIsReadOnly($bookid)) { - if ($lat !== null && $lng !== null) { - // we set the geo tag - if (!$attraction && !$house_number && !$road && !$postcode && !$city && !$state && !$country && !$address_string) { - $result = $this->contactsManager->createOrUpdate(['URI' => $uri, 'GEO' => $lat . ';' . $lng], (string)$bookid); - } - // we set the address - elseif (!$address_string) { - $street = trim($attraction . ' ' . $house_number . ' ' . $road); - $stringAddress = ';;' . $street . ';' . $city . ';' . $state . ';' . $postcode . ';' . $country; - // set the coordinates in the DB - $lat = floatval($lat); - $lng = floatval($lng); - $this->setAddressCoordinates($lat, $lng, $stringAddress, $uri); - // set the address in the vcard - $card = $this->cdBackend->getContact($bookid, $uri); - if ($card) { - $vcard = Reader::read($card['carddata']); - ; - $vcard->add(new Text($vcard, 'ADR', ['', '', $street, $city, $state, $postcode, $country], ['TYPE' => $type])); - $result = $this->cdBackend->updateCard($bookid, $uri, $vcard->serialize()); - } - } else { - $card = $this->cdBackend->getContact($bookid, $uri); - if ($card) { - $vcard = Reader::read($card['carddata']); - ; - $vcard->add(new Text($vcard, 'ADR', explode(';', $address_string), ['TYPE' => $type])); - $result = $this->cdBackend->updateCard($bookid, $uri, $vcard->serialize()); - } - } - } else { - // TODO find out how to remove a property - // following does not work properly - $result = $this->contactsManager->createOrUpdate(['URI' => $uri, 'GEO' => null], (string)$bookid); - } - return new DataResponse('EDITED'); - } else { - return new DataResponse('READONLY', 400); - } - } - } else { - $userFolder = $this->root->getUserFolder($this->userId); - $mapsFolder = $userFolder->getFirstNodeById($myMapId); - if (!($mapsFolder instanceof Folder)) { - return new DataResponse('MAP NOT FOUND', 404); - } - if (is_null($fileId)) { - $card = $this->cdBackend->getContact($bookid, $uri); - try { - /** @var File $file */ - $file = $mapsFolder->get($uri); - } catch (NotFoundException $e) { - if (!$mapsFolder->isCreatable()) { - return new DataResponse('CONTACT NOT WRITABLE', 400); - } - $file = $mapsFolder->newFile($uri); - } - } else { - $file = $mapsFolder->getFirstNodeById($fileId); - if (!($file instanceof File)) { - return new DataResponse('CONTACT NOT FOUND', 404); - } - $card = $file->getContent(); + if (strcmp($uri, 'Database:' . $uid . '.vcf') === 0 || strcmp($uid, $this->userId) === 0) { + return new DataResponse("Can't edit users", 400); } - if (!$file->isUpdateable()) { - return new DataResponse('CONTACT NOT WRITABLE', 400); - } - if ($card) { - $vcard = Reader::read($card['carddata']); + + // do not edit 'user' contact even myself + if (!$this->addressBookIsReadOnly($bookid)) { if ($lat !== null && $lng !== null) { + // we set the geo tag if (!$attraction && !$house_number && !$road && !$postcode && !$city && !$state && !$country && !$address_string) { - $vcard->add('GEO', $lat . ';' . $lng); - } elseif (!$address_string) { + $result = $this->contactsManager->createOrUpdate(['URI' => $uri, 'GEO' => $lat . ';' . $lng], (string)$bookid); + } + // we set the address + elseif (!$address_string) { $street = trim($attraction . ' ' . $house_number . ' ' . $road); $stringAddress = ';;' . $street . ';' . $city . ';' . $state . ';' . $postcode . ';' . $country; // set the coordinates in the DB $lat = floatval($lat); $lng = floatval($lng); $this->setAddressCoordinates($lat, $lng, $stringAddress, $uri); - $vcard = Reader::read($card['carddata']); - $vcard->add('ADR', ['', '', $street, $city, $state, $postcode, $country], ['TYPE' => $type]); + // set the address in the vcard + $card = $this->cdBackend->getContact($bookid, $uri); + if ($card) { + $vcard = Reader::read($card['carddata']); + ; + $vcard->add(new Text($vcard, 'ADR', ['', '', $street, $city, $state, $postcode, $country], ['TYPE' => $type])); + $result = $this->cdBackend->updateCard($bookid, $uri, $vcard->serialize()); + } } else { - $stringAddress = $address_string; - // set the coordinates in the DB - $lat = floatval($lat); - $lng = floatval($lng); - $this->setAddressCoordinates($lat, $lng, $stringAddress, $uri); - $vcard = Reader::read($card['carddata']); - $vcard->add('ADR', explode(';', $address_string), ['TYPE' => $type]); + $card = $this->cdBackend->getContact($bookid, $uri); + if ($card) { + $vcard = Reader::read($card['carddata']); + ; + $vcard->add(new Text($vcard, 'ADR', explode(';', $address_string), ['TYPE' => $type])); + $result = $this->cdBackend->updateCard($bookid, $uri, $vcard->serialize()); + } } } else { - $vcard->remove('GEO'); + // TODO find out how to remove a property + // following does not work properly + $result = $this->contactsManager->createOrUpdate(['URI' => $uri, 'GEO' => null], (string)$bookid); } - $file->putContent($vcard->serialize()); + + // check addressbook permissions return new DataResponse('EDITED'); } - return new DataResponse('CONTACT NOT FOUND', 404); + + return new DataResponse('READONLY', 400); + } + + $userFolder = $this->root->getUserFolder($this->userId); + $mapsFolder = $userFolder->getFirstNodeById($myMapId); + if (!($mapsFolder instanceof Folder)) { + return new DataResponse('MAP NOT FOUND', 404); + } + + if (is_null($fileId)) { + $card = $this->cdBackend->getContact($bookid, $uri); + try { + /** @var File $file */ + $file = $mapsFolder->get($uri); + } catch (NotFoundException) { + if (!$mapsFolder->isCreatable()) { + return new DataResponse('CONTACT NOT WRITABLE', 400); + } + + $file = $mapsFolder->newFile($uri); + } + } else { + $file = $mapsFolder->getFirstNodeById($fileId); + if (!($file instanceof File)) { + return new DataResponse('CONTACT NOT FOUND', 404); + } + + $card = $file->getContent(); + } + + if (!$file->isUpdateable()) { + return new DataResponse('CONTACT NOT WRITABLE', 400); } + if ($card) { + $vcard = Reader::read($card['carddata']); + if ($lat !== null && $lng !== null) { + if (!$attraction && !$house_number && !$road && !$postcode && !$city && !$state && !$country && !$address_string) { + $vcard->add('GEO', $lat . ';' . $lng); + } elseif (!$address_string) { + $street = trim($attraction . ' ' . $house_number . ' ' . $road); + $stringAddress = ';;' . $street . ';' . $city . ';' . $state . ';' . $postcode . ';' . $country; + // set the coordinates in the DB + $lat = floatval($lat); + $lng = floatval($lng); + $this->setAddressCoordinates($lat, $lng, $stringAddress, $uri); + $vcard = Reader::read($card['carddata']); + $vcard->add('ADR', ['', '', $street, $city, $state, $postcode, $country], ['TYPE' => $type]); + } else { + $stringAddress = $address_string; + // set the coordinates in the DB + $lat = floatval($lat); + $lng = floatval($lng); + $this->setAddressCoordinates($lat, $lng, $stringAddress, $uri); + $vcard = Reader::read($card['carddata']); + $vcard->add('ADR', explode(';', $address_string), ['TYPE' => $type]); + } + } else { + $vcard->remove('GEO'); + } + + $file->putContent($vcard->serialize()); + return new DataResponse('EDITED'); + } + + return new DataResponse('CONTACT NOT FOUND', 404); } /** * @throws \OCP\Files\NotPermittedException - * @throws \OC\User\NoUserException + * @throws NoUserException */ #[NoAdminRequired] public function addContactToMap(int $bookid, string $uri, int $myMapId, ?int $fileId = null): DataResponse { @@ -531,15 +521,17 @@ public function addContactToMap(int $bookid, string $uri, int $myMapId, ?int $fi if (!($mapsFolder instanceof Folder)) { return new DataResponse('MAP NOT FOUND', 404); } + if (is_null($fileId)) { $card = $this->cdBackend->getContact($bookid, $uri); try { /** @var File $file */ $file = $mapsFolder->get($uri); - } catch (NotFoundException $e) { + } catch (NotFoundException) { if (!$mapsFolder->isCreatable()) { return new DataResponse('CONTACT NOT WRITABLE', 400); } + $file = $mapsFolder->newFile($uri); } } else { @@ -547,16 +539,20 @@ public function addContactToMap(int $bookid, string $uri, int $myMapId, ?int $fi if (!($file instanceof File)) { return new DataResponse('CONTACT NOT FOUND', 404); } + $card = $file->getContent(); } + if (!$file->isUpdateable()) { return new DataResponse('CONTACT NOT WRITABLE', 400); } + if ($card) { $vcard = Reader::read($card['carddata']); $file->putContent($vcard->serialize()); return new DataResponse('DONE'); } + return new DataResponse('CONTACT NOT FOUND', 404); } @@ -564,9 +560,10 @@ private function addressBookIsReadOnly(int $bookid): bool { $userBooks = $this->cdBackend->getAddressBooksForUser('principals/users/' . $this->userId); foreach ($userBooks as $book) { if ($book['id'] === $bookid) { - return (isset($book['{http://owncloud.org/ns}read-only']) and $book['{http://owncloud.org/ns}read-only']); + return (isset($book['{http://owncloud.org/ns}read-only']) && $book['{http://owncloud.org/ns}read-only']); } } + return true; } @@ -577,9 +574,10 @@ private function getAddressBooksReadOnly(): array { $booksReadOnly = []; $userBooks = $this->cdBackend->getAddressBooksForUser('principals/users/' . $this->userId); foreach ($userBooks as $book) { - $ro = (isset($book['{http://owncloud.org/ns}read-only']) and $book['{http://owncloud.org/ns}read-only']); + $ro = (isset($book['{http://owncloud.org/ns}read-only']) && $book['{http://owncloud.org/ns}read-only']); $booksReadOnly[$book['id']] = $ro; } + return $booksReadOnly; } @@ -588,7 +586,7 @@ private function getAddressBooksReadOnly(): array { */ private function setAddressCoordinates(float $lat, float $lng, string $adr, string $uri): void { $qb = $this->dbconnection->getQueryBuilder(); - $adr_norm = strtolower(preg_replace('/\s+/', '', $adr)); + $adr_norm = strtolower((string)preg_replace('/\s+/', '', $adr)); $qb->select('id') ->from('maps_address_geo') @@ -663,14 +661,15 @@ public function deleteContactAddress(int $bookid, string $uri, string $uid, stri } } } + $this->cdBackend->updateCard($bookid, $uri, $vcard->serialize()); // no need to cleanup db here, it will be done when catching vcard change hook return new DataResponse('DELETED'); - } else { - return new DataResponse('READONLY', 400); } - } else { - return new DataResponse('FAILED', 400); + + return new DataResponse('READONLY', 400); } + + return new DataResponse('FAILED', 400); } } diff --git a/lib/Controller/DevicesApiController.php b/lib/Controller/DevicesApiController.php index f7e157f4d..2f61c071d 100644 --- a/lib/Controller/DevicesApiController.php +++ b/lib/Controller/DevicesApiController.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; use OCA\Maps\Service\DevicesService; @@ -26,9 +27,9 @@ class DevicesApiController extends ApiController { public function __construct( string $appName, IRequest $request, - private IL10N $l, - private DevicesService $devicesService, - private string $userId, + private readonly IL10N $l, + private readonly DevicesService $devicesService, + private readonly ?string $userId, ) { parent::__construct($appName, $request, 'PUT, POST, GET, DELETE, PATCH, OPTIONS', @@ -51,6 +52,7 @@ public function getDevices($apiversion): DataResponse { if ($this->request->getHeader('If-None-Match') === '"' . $etag . '"') { return new DataResponse([], Http::STATUS_NOT_MODIFIED); } + return (new DataResponse($devices)) ->setLastModified($now) ->setETag($etag); @@ -73,13 +75,12 @@ public function getDevicePoints(int $id, int $pruneBefore = 0): DataResponse { * @param $altitude * @param $battery * @param $accuracy - * @return DataResponse */ #[NoAdminRequired] #[NoCSRFRequired] #[CORS] public function addDevicePoint($apiversion, $lat, $lng, $timestamp = null, $user_agent = null, $altitude = null, $battery = null, $accuracy = null): DataResponse { - if (is_numeric($lat) and is_numeric($lng)) { + if (is_numeric($lat) && is_numeric($lng)) { $timestamp = $this->normalizeOptionalNumber($timestamp); $altitude = $this->normalizeOptionalNumber($altitude); $battery = $this->normalizeOptionalNumber($battery); @@ -88,25 +89,26 @@ public function addDevicePoint($apiversion, $lat, $lng, $timestamp = null, $user if ($timestamp === null) { $ts = (new \DateTime())->getTimestamp(); } + $ua = $user_agent; if ($user_agent === null) { $ua = $_SERVER['HTTP_USER_AGENT']; } + $deviceId = $this->devicesService->getOrCreateDeviceFromDB($this->userId, $ua); $pointId = $this->devicesService->addPointToDB($deviceId, $lat, $lng, $ts, $altitude, $battery, $accuracy); return new DataResponse([ 'deviceId' => $deviceId, 'pointId' => $pointId ]); - } else { - return new DataResponse($this->l->t('Invalid values'), 400); } + + return new DataResponse($this->l->t('Invalid values'), 400); } /** * @param $id * @param $color - * @return DataResponse */ #[NoAdminRequired] #[NoCSRFRequired] @@ -114,16 +116,16 @@ public function addDevicePoint($apiversion, $lat, $lng, $timestamp = null, $user public function editDevice(int $id, $color): DataResponse { $device = $this->devicesService->getDeviceFromDB($id, $this->userId); if ($device !== null) { - if (is_string($color) && strlen($color) > 0) { + if (is_string($color) && $color !== '') { $this->devicesService->editDeviceInDB($id, $color, null); $editedDevice = $this->devicesService->getDeviceFromDB($id, $this->userId); return new DataResponse($editedDevice); - } else { - return new DataResponse($this->l->t('Invalid values'), 400); } - } else { - return new DataResponse($this->l->t('No such device'), 400); + + return new DataResponse($this->l->t('Invalid values'), 400); } + + return new DataResponse($this->l->t('No such device'), 400); } #[NoAdminRequired] @@ -134,9 +136,9 @@ public function deleteDevice(int $id): DataResponse { if ($device !== null) { $this->devicesService->deleteDeviceFromDB($id); return new DataResponse('DELETED'); - } else { - return new DataResponse($this->l->t('No such device'), 400); } + + return new DataResponse($this->l->t('No such device'), 400); } /** @@ -147,6 +149,7 @@ private function normalizeOptionalNumber($value) { if (!is_numeric($value)) { return null; } + return $value; } diff --git a/lib/Controller/DevicesController.php b/lib/Controller/DevicesController.php index 9b4a6c72e..1dd379ae5 100644 --- a/lib/Controller/DevicesController.php +++ b/lib/Controller/DevicesController.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; +use OC\User\NoUserException; use OCA\Maps\DB\DeviceShareMapper; use OCA\Maps\Service\DevicesService; use OCP\AppFramework\Controller; @@ -31,18 +33,19 @@ class DevicesController extends Controller { private ?Folder $userFolder = null; - private string $appVersion; + + private readonly string $appVersion; public function __construct( string $appName, IRequest $request, IAppConfig $appConfig, - private IL10N $l, - private DevicesService $devicesService, - private DeviceShareMapper $deviceShareMapper, - private IDateTimeZone $dateTimeZone, - private IRootFolder $root, - private ?string $userId, + private readonly IL10N $l, + private readonly DevicesService $devicesService, + private readonly DeviceShareMapper $deviceShareMapper, + private readonly IDateTimeZone $dateTimeZone, + private readonly IRootFolder $root, + private readonly ?string $userId, ) { parent::__construct($appName, $request); $this->appVersion = $appConfig->getValueString('maps', 'installed_version'); @@ -60,6 +63,7 @@ public function getDevices(?array $tokens = null, ?int $myMapId = null): DataRes if (is_null($tokens)) { $tokens = []; } + if (is_null($myMapId)) { $devices = $this->devicesService->getDevicesFromDB($this->userId); $deviceIds = array_column($devices, 'id'); @@ -74,10 +78,12 @@ public function getDevices(?array $tokens = null, ?int $myMapId = null): DataRes if (!$folder instanceof Folder) { return new DataResponse($this->l->t('Map not Found'), 404); } + $shares = $this->devicesService->getSharedDevicesFromFolder($folder); $st = array_column($shares, 'token'); $tokens = array_merge($tokens, $st); } + $td = $this->devicesService->getDevicesByTokens($tokens); $devices = $td + $devices; return new DataResponse(array_values($devices)); @@ -99,55 +105,51 @@ public function getDevicePoints(int $id, ?int $pruneBefore = 0, ?int $limit = 10 } else { $points = $this->devicesService->getDevicePointsByTokens($tokens, $pruneBefore, $limit, $offset); } + return new DataResponse($points); } /** * @param $lat * @param $lng - * @param null $timestamp - * @param null $user_agent - * @param null $altitude - * @param null $battery - * @param null $accuracy - * @return DataResponse */ #[NoAdminRequired] - public function addDevicePoint($lat, $lng, $timestamp = null, $user_agent = null, $altitude = null, $battery = null, $accuracy = null): DataResponse { - if (is_numeric($lat) and is_numeric($lng)) { - $ts = $timestamp; + public function addDevicePoint($lat, $lng, ?int $timestamp = null, ?string $user_agent = null, $altitude = null, $battery = null, $accuracy = null): DataResponse { + if (is_numeric($lat) && is_numeric($lng)) { if ($timestamp === null) { - $ts = (new \DateTime())->getTimestamp(); + $timestamp = (new \DateTime())->getTimestamp(); } + $ua = $user_agent; if ($user_agent === null) { $ua = $_SERVER['HTTP_USER_AGENT']; } + $deviceId = $this->devicesService->getOrCreateDeviceFromDB($this->userId, $ua); - $pointId = $this->devicesService->addPointToDB($deviceId, $lat, $lng, $ts, $altitude, $battery, $accuracy); + $pointId = $this->devicesService->addPointToDB($deviceId, $lat, $lng, $timestamp, $altitude, $battery, $accuracy); return new DataResponse([ 'deviceId' => $deviceId, 'pointId' => $pointId ]); - } else { - return new DataResponse('Invalid values', 400); } + + return new DataResponse('Invalid values', 400); } #[NoAdminRequired] public function editDevice(int $id, string $color, string $name): DataResponse { $device = $this->devicesService->getDeviceFromDB($id, $this->userId); if ($device !== null) { - if (strlen($color) > 0 || strlen($name) > 0) { + if ($color !== '' || $name !== '') { $this->devicesService->editDeviceInDB($id, $color, $name); $editedDevice = $this->devicesService->getDeviceFromDB($id, $this->userId); return new DataResponse($editedDevice); - } else { - return new DataResponse($this->l->t('Invalid values'), 400); } - } else { - return new DataResponse($this->l->t('No such device'), 400); + + return new DataResponse($this->l->t('Invalid values'), 400); } + + return new DataResponse($this->l->t('No such device'), 400); } #[NoAdminRequired] @@ -157,15 +159,15 @@ public function deleteDevice(int $id): DataResponse { $this->devicesService->deleteDeviceFromDB($id); $this->deviceShareMapper->removeAllByDeviceId($id); return new DataResponse('DELETED'); - } else { - return new DataResponse($this->l->t('No such device'), 400); } + + return new DataResponse($this->l->t('No such device'), 400); } /** * @param ?array $deviceIdList - * @param int $begin - * @param int $end + * @param ?int $begin + * @param ?int $end * @param bool $all=false * @throws \OCP\Files\NotFoundException * @throws \OCP\Files\NotPermittedException @@ -174,7 +176,7 @@ public function deleteDevice(int $id): DataResponse { public function exportDevices($deviceIdList, $begin, $end, bool $all = false): DataResponse { // sorry about ugly deviceIdList management: // when an empty list is passed in http request, we get null here - if ($deviceIdList === null or (is_array($deviceIdList) and count($deviceIdList) === 0)) { + if ($deviceIdList === null || is_array($deviceIdList) && $deviceIdList === []) { return new DataResponse($this->l->t('No device to export'), 400); } @@ -183,11 +185,14 @@ public function exportDevices($deviceIdList, $begin, $end, bool $all = false): D if (!$userFolder->nodeExists('/Maps')) { $userFolder->newFolder('Maps'); } + if ($userFolder->nodeExists('/Maps')) { $mapsFolder = $userFolder->get('/Maps'); if (!$mapsFolder instanceof Folder) { return new DataResponse($this->l->t('/Maps is not a directory'), 400); - } elseif (!$mapsFolder->isCreatable()) { + } + + if (!$mapsFolder->isCreatable()) { return new DataResponse($this->l->t('/Maps directory is not writeable'), 400); } } else { @@ -209,6 +214,7 @@ public function exportDevices($deviceIdList, $begin, $end, bool $all = false): D if ($mapsFolder->nodeExists($filename)) { $mapsFolder->get($filename)->delete(); } + $file = $mapsFolder->newFile($filename); $handler = $file->fopen('w'); @@ -221,7 +227,6 @@ public function exportDevices($deviceIdList, $begin, $end, bool $all = false): D /** * @param $path - * @return DataResponse * @throws \OCP\Files\InvalidPathException * @throws \OCP\Files\NotFoundException */ @@ -237,23 +242,23 @@ public function importDevices($path): DataResponse { if (str_ends_with($lowerFileName, '.gpx') || str_ends_with($lowerFileName, '.kml') || str_ends_with($lowerFileName, '.kmz')) { $nbImported = $this->devicesService->importDevices($this->userId, $file); return new DataResponse($nbImported); - } else { - // invalid extension - return new DataResponse($this->l->t('Invalid file extension'), 400); } - } else { - // directory or not readable - return new DataResponse($this->l->t('Impossible to read the file'), 400); + + // invalid extension + return new DataResponse($this->l->t('Invalid file extension'), 400); } - } else { - // does not exist - return new DataResponse($this->l->t('File does not exist'), 400); + + // directory or not readable + return new DataResponse($this->l->t('Impossible to read the file'), 400); } + + // does not exist + return new DataResponse($this->l->t('File does not exist'), 400); } /** * @throws \OCP\Files\NotPermittedException - * @throws \OC\User\NoUserException + * @throws NoUserException */ #[NoAdminRequired] public function getSharedDevices(?int $myMapId = null): DataResponse { @@ -291,12 +296,13 @@ public function removeDeviceShare(string $token): DataResponse { } catch (DoesNotExistException) { throw new NotFoundException(); } + $device = $this->devicesService->getDeviceFromDB($share->getDeviceId(), $this->userId); if ($device !== null) { return new DataResponse($this->deviceShareMapper->removeById($share->getId())); - } else { - throw new NotFoundException(); } + + throw new NotFoundException(); } /** @@ -306,25 +312,29 @@ public function removeDeviceShare(string $token): DataResponse { public function addSharedDeviceToMap(string $token, int $targetMapId): DataResponse { try { $share = $this->deviceShareMapper->findByToken($token); - } catch (DoesNotExistException $e) { + } catch (DoesNotExistException) { return new DataResponse($this->l->t('Share not Found'), 404); } + $folder = $this->userFolder->getFirstNodeById($targetMapId); if (!$folder instanceof Folder) { return new DataResponse($this->l->t('Map not Found'), 404); } + try { /** @var File $file */ $file = $folder->get('.device_shares.json'); - } catch (\OCP\Files\NotFoundException $e) { + } catch (NotFoundException) { $file = $folder->newFile('.device_shares.json', '[]'); } - $data = json_decode($file->getContent(), true); + + $data = json_decode((string)$file->getContent(), true); foreach ($data as $s) { if ($s->token == $share->getToken()) { return new DataResponse($this->l->t('Share was already on map')); } } + $data[] = $share; $file->putContent(json_encode($data, JSON_PRETTY_PRINT)); return new DataResponse('Done'); @@ -335,13 +345,15 @@ public function removeSharedDeviceFromMap(string $token, int $myMapId): DataResp if (!$folder instanceof Folder) { return new DataResponse($this->l->t('Map not Found'), 404); } + try { /** @var File $file */ $file = $folder->get('.device_shares.json'); - } catch (\OCP\Files\NotFoundException $e) { + } catch (NotFoundException) { $file = $folder->newFile('.device_shares.json', '[]'); } - $data = json_decode($file->getContent(), true); + + $data = json_decode((string)$file->getContent(), true); $shares = []; $deleted = null; foreach ($data as $share) { @@ -352,10 +364,12 @@ public function removeSharedDeviceFromMap(string $token, int $myMapId): DataResp $shares[] = $share; } } + $file->putContent(json_encode($shares, JSON_PRETTY_PRINT)); if (is_null($deleted)) { return new DataResponse('Failed', 500); } + return new DataResponse('Done'); } } diff --git a/lib/Controller/FavoritesApiController.php b/lib/Controller/FavoritesApiController.php index 90927477c..ff2f117ce 100644 --- a/lib/Controller/FavoritesApiController.php +++ b/lib/Controller/FavoritesApiController.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; use OCA\Maps\Service\FavoritesService; @@ -26,9 +27,9 @@ class FavoritesApiController extends ApiController { public function __construct( string $appName, IRequest $request, - private IL10N $l, - private FavoritesService $favoritesService, - private ?string $userId, + private readonly IL10N $l, + private readonly FavoritesService $favoritesService, + private readonly ?string $userId, ) { parent::__construct($appName, $request, 'PUT, POST, GET, DELETE, PATCH, OPTIONS', @@ -51,6 +52,7 @@ public function getFavorites($apiversion, int $pruneBefore = 0): DataResponse { if ($this->request->getHeader('If-None-Match') === '"' . $etag . '"') { return new DataResponse([], Http::STATUS_NOT_MODIFIED); } + return (new DataResponse($favorites)) ->setLastModified($now) ->setETag($etag); @@ -64,19 +66,18 @@ public function getFavorites($apiversion, int $pruneBefore = 0): DataResponse { * @param $category * @param $comment * @param $extensions - * @return DataResponse */ #[NoAdminRequired] #[NoCSRFRequired] #[CORS] public function addFavorite($apiversion, $name, $lat, $lng, $category, $comment, $extensions): DataResponse { - if (is_numeric($lat) && is_numeric($lng)) { + if (is_float($lat) && is_float($lng)) { $favoriteId = $this->favoritesService->addFavoriteToDB($this->userId, $name, $lat, $lng, $category, $comment, $extensions); $favorite = $this->favoritesService->getFavoriteFromDB($favoriteId); return new DataResponse($favorite); - } else { - return new DataResponse($this->l->t('Invalid values'), 400); } + + return new DataResponse($this->l->t('Invalid values'), 400); } /** @@ -93,18 +94,16 @@ public function addFavorite($apiversion, $name, $lat, $lng, $category, $comment, public function editFavorite(int $id, $name, $lat, $lng, $category, $comment, $extensions): DataResponse { $favorite = $this->favoritesService->getFavoriteFromDB($id, $this->userId); if ($favorite !== null) { - if (($lat === null || is_numeric($lat)) - && ($lng === null || is_numeric($lng)) - ) { + if (($lat === null || is_float($lat)) && ($lng === null || is_float($lng))) { $this->favoritesService->editFavoriteInDB($id, $name, $lat, $lng, $category, $comment, $extensions); $editedFavorite = $this->favoritesService->getFavoriteFromDB($id); return new DataResponse($editedFavorite); - } else { - return new DataResponse($this->l->t('Invalid values'), 400); } - } else { - return new DataResponse($this->l->t('No such favorite'), 400); + + return new DataResponse($this->l->t('Invalid values'), 400); } + + return new DataResponse($this->l->t('No such favorite'), 400); } #[NoAdminRequired] @@ -115,9 +114,9 @@ public function deleteFavorite(int $id): DataResponse { if ($favorite !== null) { $this->favoritesService->deleteFavoriteFromDB($id); return new DataResponse('DELETED'); - } else { - return new DataResponse($this->l->t('No such favorite'), 400); } + + return new DataResponse($this->l->t('No such favorite'), 400); } } diff --git a/lib/Controller/FavoritesController.php b/lib/Controller/FavoritesController.php index 088224365..f2c97bc14 100644 --- a/lib/Controller/FavoritesController.php +++ b/lib/Controller/FavoritesController.php @@ -1,5 +1,7 @@ appVersion = $appConfig->getValueString('maps', 'installed_version'); // IConfig object - if ($userId !== '' and $userId !== null) { + if ($userId !== '' && $userId !== null) { // path of user files folder relative to DATA folder $this->userFolder = $rootFolder->getUserFolder($userId); } + $this->defaultFavoritsJSON = json_encode([ 'type' => 'FeatureCollection', 'features' => [] @@ -63,16 +69,15 @@ public function __construct( } /** - * @param Folder $folder - * @return mixed * @throws \OCP\Files\NotPermittedException */ private function getJSONFavoritesFile(Folder $folder): Node { try { $file = $folder->get('.favorites.json'); - } catch (NotFoundException $e) { + } catch (NotFoundException) { $file = $folder->newFile('.favorites.json', $this->defaultFavoritsJSON); } + return $file; } @@ -86,23 +91,19 @@ public function getFavorites(?int $myMapId = null): DataResponse { } else { $folder = $this->userFolder->getFirstNodeById($myMapId); if (!$folder instanceof Folder) { - throw new NotFoundException("Folder with id $myMapId does not exist"); + throw new NotFoundException(sprintf('Folder with id %d does not exist', $myMapId)); } + $file = $this->getJSONFavoritesFile($folder); $favorites = $this->favoritesService->getFavoritesFromJSON($file); } + return new DataResponse($favorites); } /** - * @param string|null $name * @param float $lat * @param float $lng - * @param string|null $category - * @param string|null $comment - * @param string|null $extensions - * @param int|null $myMapId - * @return DataResponse * @throws NotFoundException * @throws \OCP\Files\InvalidPathException * @throws \OCP\Files\NotPermittedException @@ -112,30 +113,30 @@ public function addFavorite(?string $name, ?float $lat, ?float $lng, ?string $ca if (!is_numeric($lat) || !is_numeric($lng)) { return new DataResponse($this->l->t('Invalid values'), 400); } + if (is_null($myMapId)) { $favoriteId = $this->favoritesService->addFavoriteToDB($this->userId, $name, $lat, $lng, $category, $comment, $extensions); $favorite = $this->favoritesService->getFavoriteFromDB($favoriteId); return new DataResponse($favorite); - } else { - $folders = $this->userFolder->getById($myMapId); - if (!empty($folders) && $this->userFolder->getId() === $myMapId) { - $folders[] = $this->userFolder; - } - $folder = array_shift($folders); - if (!($folder instanceof Folder)) { - return new DataResponse('Map not found', 404); - } - $file = $this->getJSONFavoritesFile($folder); - $favoriteId = $this->favoritesService->addFavoriteToJSON($file, $name, $lat, $lng, $category, $comment, $extensions); - $favorite = $this->favoritesService->getFavoriteFromJSON($file, $favoriteId); - return new DataResponse($favorite); } + + $folders = $this->userFolder->getById($myMapId); + if (!empty($folders) && $this->userFolder->getId() === $myMapId) { + $folders[] = $this->userFolder; + } + + $folder = array_shift($folders); + if (!($folder instanceof Folder)) { + return new DataResponse('Map not found', 404); + } + + $file = $this->getJSONFavoritesFile($folder); + $favoriteId = $this->favoritesService->addFavoriteToJSON($file, $name, $lat, $lng, $category, $comment, $extensions); + $favorite = $this->favoritesService->getFavoriteFromJSON($file, $favoriteId); + return new DataResponse($favorite); } /** - * @param array $favorites - * @param int|null $myMapId - * @return DataResponse * @throws NotFoundException * @throws \OCP\Files\InvalidPathException * @throws \OCP\Files\NotPermittedException @@ -145,33 +146,37 @@ public function addFavorites(array $favorites, ?int $myMapId = null): DataRespon if (is_null($myMapId)) { $favoritesAfter = []; foreach ($favorites as $favorite) { - if (is_numeric($favorite->lat) && is_numeric($favorite->lng)) { + if (is_float($favorite->lat) && is_float($favorite->lng)) { $favoriteId = $this->favoritesService->addFavoriteToDB($this->userId, $favorite->name, $favorite->lat, $favorite->lng, $favorite->category, $favorite->comment, $favorite->extensions); $favoritesAfter[] = $this->favoritesService->getFavoriteFromDB($favoriteId); } else { return new DataResponse('invalid values', 400); } } + return new DataResponse($favoritesAfter); - } else { - $folders = $this->userFolder->getById($myMapId); - if (!empty($folders) && $this->userFolder->getId() === $myMapId) { - $folders[] = $this->userFolder; - } - $folder = array_shift($folders); - if (!$folder instanceof Folder) { - return new DataResponse('Map not found', 404); + } + + $folders = $this->userFolder->getById($myMapId); + if (!empty($folders) && $this->userFolder->getId() === $myMapId) { + $folders[] = $this->userFolder; + } + + $folder = array_shift($folders); + if (!$folder instanceof Folder) { + return new DataResponse('Map not found', 404); + } + + $file = $this->getJSONFavoritesFile($folder); + $favoriteIds = $this->favoritesService->addFavoritesToJSON($file, $favorites); + $favoritesAfter = []; + foreach ($this->favoritesService->getFavoritesFromJSON($file) as $favorite) { + if (in_array($favorite['id'], $favoriteIds)) { + $favoritesAfter[] = $favorite; } - $file = $this->getJSONFavoritesFile($folder); - $favoriteIds = $this->favoritesService->addFavoritesToJSON($file, $favorites); - $favoritesAfter = []; - foreach ($this->favoritesService->getFavoritesFromJSON($file) as $favorite) { - if (in_array($favorite['id'], $favoriteIds)) { - $favoritesAfter[] = $favorite; - } - }; - return new DataResponse($favoritesAfter); } + + return new DataResponse($favoritesAfter); } /** @@ -186,6 +191,7 @@ public function editFavorite(int $id, ?string $name, ?float $lat, ?float $lng, ? $editedFavorite = $this->favoritesService->getFavoriteFromDB($id); return new DataResponse($editedFavorite); } + return new DataResponse($this->l->t('no such favorite'), 400); } @@ -193,11 +199,13 @@ public function editFavorite(int $id, ?string $name, ?float $lat, ?float $lng, ? if (!$folder instanceof Folder) { return new DataResponse('Map not found', 404); } + $file = $this->getJSONFavoritesFile($folder); - $favorite = $this->favoritesService->getFavoriteFromJSON($file, $id, $this->userId); + $favorite = $this->favoritesService->getFavoriteFromJSON($file, $id); if ($favorite === null) { return new DataResponse($this->l->t('no such favorite'), 400); } + $this->favoritesService->editFavoriteInJSON($file, $id, $name, $lat, $lng, $category, $comment, $extensions); $editedFavorite = $this->favoritesService->getFavoriteFromJSON($file, $id); return new DataResponse($editedFavorite); @@ -209,35 +217,32 @@ public function editFavorite(int $id, ?string $name, ?float $lat, ?float $lng, ? */ #[NoAdminRequired] public function renameCategories(array $categories, string $newName, ?int $myMapId = null): DataResponse { - if (is_array($categories)) { - foreach ($categories as $cat) { - if (is_null($myMapId)) { - $this->favoritesService->renameCategoryInDB($this->userId, $cat, $newName); - - // Rename share if one exists - try { - $share = $this->favoriteShareMapper->findByOwnerAndCategory($this->userId, $cat); - $share->setCategory($newName); - $this->favoriteShareMapper->update($share); - } catch (DoesNotExistException|MultipleObjectsReturnedException $e) { - } - } else { - $folder = $this->userFolder->getFirstNodeById($myMapId); - if (!$folder instanceof Folder) { - return new DataResponse('Map not found', 404); - } - $file = $this->getJSONFavoritesFile($folder); - $this->favoritesService->renameCategoryInJSON($file, $cat, $newName); + foreach ($categories as $cat) { + if (is_null($myMapId)) { + $this->favoritesService->renameCategoryInDB($this->userId, $cat, $newName); + + // Rename share if one exists + try { + $share = $this->favoriteShareMapper->findByOwnerAndCategory($this->userId, $cat); + $share->setCategory($newName); + $this->favoriteShareMapper->update($share); + } catch (DoesNotExistException|MultipleObjectsReturnedException) { + } + } else { + $folder = $this->userFolder->getFirstNodeById($myMapId); + if (!$folder instanceof Folder) { + return new DataResponse('Map not found', 404); } + + $file = $this->getJSONFavoritesFile($folder); + $this->favoritesService->renameCategoryInJSON($file, $cat, $newName); } } + return new DataResponse('RENAMED'); } /** - * @param int $id - * @param int|null $myMapId - * @return DataResponse * @throws \OCP\Files\NotPermittedException */ #[NoAdminRequired] @@ -248,23 +253,24 @@ public function deleteFavorite(int $id, ?int $myMapId = null): DataResponse { $this->favoritesService->deleteFavoriteFromDB($id); return new DataResponse('DELETED'); } + return new DataResponse($this->l->t('no such favorite'), 400); } + $folder = $this->userFolder->getFirstNodeById($myMapId); if (!$folder instanceof Folder) { return new DataResponse('Map not found', 404); } + $file = $this->getJSONFavoritesFile($folder); if ($this->favoritesService->deleteFavoriteFromJSON($file, $id) > 0) { return new DataResponse('DELETED'); } + return new DataResponse($this->l->t('no such favorite'), 400); } /** - * @param array $ids - * @param int|null $myMapId - * @return DataResponse * @throws \OCP\Files\NotPermittedException */ #[NoAdminRequired] @@ -276,15 +282,17 @@ public function deleteFavorites(array $ids, ?int $myMapId = null): DataResponse if (!$folder instanceof Folder) { return new DataResponse('Map not found', 404); } + $file = $this->getJSONFavoritesFile($folder); $this->favoritesService->deleteFavoritesFromJSON($file, $ids); } + return new DataResponse('DELETED'); } /** * @throws \OCP\Files\NotPermittedException - * @throws \OC\User\NoUserException + * @throws NoUserException */ #[NoAdminRequired] public function getSharedCategories(?int $myMapId = null): DataResponse { @@ -305,7 +313,7 @@ public function shareCategory(string $category): DataResponse { $share = $this->favoriteShareMapper->findOrCreateByOwnerAndCategory($this->userId, $category); - if ($share === null) { + if (!$share instanceof FavoriteShare) { return new DataResponse($this->l->t('Error sharing favorite'), Http::STATUS_INTERNAL_SERVER_ERROR); } @@ -326,38 +334,38 @@ public function unShareCategory(string $category): DataResponse { } /** - * @param string $category - * @param int $targetMapId - * @param int|null $myMapId - * @return DataResponse * @throws DoesNotExistException * @throws MultipleObjectsReturnedException * @throws \OCP\Files\NotPermittedException - * @throws \OC\User\NoUserException + * @throws NoUserException */ #[NoAdminRequired] public function addShareCategoryToMap(string $category, int $targetMapId, ?int $myMapId = null): DataResponse { - if (is_null($myMapId) || $myMapId === '') { + if (is_null($myMapId) || $myMapId === 0) { $share = $this->favoriteShareMapper->findByOwnerAndCategory($this->userId, $category); } else { $share = $this->favoriteShareMapper->findByMapIdAndCategory($this->userId, $myMapId, $category); } + $folders = $this->userFolder->getById($targetMapId); $folder = array_shift($folders); if (!($folder instanceof Folder)) { return new DataResponse($this->l->t('Map not Found'), 404); } + try { $file = $folder->get('.favorite_shares.json'); - } catch (NotFoundException $e) { + } catch (NotFoundException) { $file = $folder->newFile('.favorite_shares.json', $content = '[]'); } - $data = json_decode($file->getContent(), true); + + $data = json_decode((string)$file->getContent(), true); foreach ($data as $s) { if ($s->token === $share->token) { return new DataResponse($this->l->t('Share was already on map')); } } + $share->id = count($data); $data[] = $share; $file->putContent(json_encode($data, JSON_PRETTY_PRINT)); @@ -370,15 +378,11 @@ public function removeShareCategoryFromMap(string $category, int $myMapId): Data if (is_null($d)) { return new DataResponse('Failed', 500); } + return new DataResponse('Done'); } /** - * @param array|null $categoryList - * @param int|null $begin - * @param int|null $end - * @param bool $all - * @return DataResponse * @throws NotFoundException * @throws \OCP\Files\NotPermittedException */ @@ -386,9 +390,8 @@ public function removeShareCategoryFromMap(string $category, int $myMapId): Data public function exportFavorites(?array $categoryList = null, ?int $begin = null, ?int $end = null, bool $all = false): DataResponse { // sorry about ugly categoryList management: // when an empty list is passed in http request, we get null here - if ($categoryList === null or (is_array($categoryList) and count($categoryList) === 0)) { - $response = new DataResponse($this->l->t('Nothing to export'), 400); - return $response; + if ($categoryList === null || is_array($categoryList) && $categoryList === []) { + return new DataResponse($this->l->t('Nothing to export'), 400); } // create /Maps directory if necessary @@ -396,24 +399,23 @@ public function exportFavorites(?array $categoryList = null, ?int $begin = null, if (!$userFolder->nodeExists('/Maps')) { $userFolder->newFolder('Maps'); } + if ($userFolder->nodeExists('/Maps')) { $mapsFolder = $userFolder->get('/Maps'); if (!($mapsFolder instanceof Folder)) { - $response = new DataResponse($this->l->t('/Maps is not a directory'), 400); - return $response; - } elseif (!$mapsFolder->isCreatable()) { - $response = new DataResponse($this->l->t('/Maps directory is not writeable'), 400); - return $response; + return new DataResponse($this->l->t('/Maps is not a directory'), 400); + } + + if (!$mapsFolder->isCreatable()) { + return new DataResponse($this->l->t('/Maps directory is not writeable'), 400); } } else { - $response = new DataResponse($this->l->t('Impossible to create /Maps directory'), 400); - return $response; + return new DataResponse($this->l->t('Impossible to create /Maps directory'), 400); } $nbFavorites = $this->favoritesService->countFavorites($this->userId, $categoryList, $begin, $end); if ($nbFavorites === 0) { - $response = new DataResponse($this->l->t('Nothing to export'), 400); - return $response; + return new DataResponse($this->l->t('Nothing to export'), 400); } // generate export file name @@ -426,6 +428,7 @@ public function exportFavorites(?array $categoryList = null, ?int $begin = null, if ($mapsFolder->nodeExists($filename)) { $mapsFolder->get($filename)->delete(); } + $file = $mapsFolder->newFile($filename); $handler = $file->fopen('w'); @@ -463,9 +466,9 @@ public function importFavorites(string $path): DataResponse { || str_ends_with($lowerFileName, '.geojson')) { $result = $this->favoritesService->importFavorites($this->userId, $file); return new DataResponse($result); - } else { - // invalid extension - return new DataResponse($this->l->t('Invalid file extension'), 400); } + + // invalid extension + return new DataResponse($this->l->t('Invalid file extension'), 400); } } diff --git a/lib/Controller/MyMapsController.php b/lib/Controller/MyMapsController.php index 3a4507278..b79247fc4 100644 --- a/lib/Controller/MyMapsController.php +++ b/lib/Controller/MyMapsController.php @@ -1,5 +1,7 @@ myMapsService = $myMapsService; - $this->userId = $userId; } /** @@ -41,6 +42,7 @@ public function addMyMap(array $values): DataResponse { if (is_string($myMap)) { new DataResponse($myMap, 400); } + return new DataResponse($myMap); } diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php index d33e44a02..260d53508 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -1,5 +1,7 @@ * @copyright Vinzenz Rosenkranz 2017 */ - namespace OCA\Maps\Controller; use OCA\Files\Event\LoadSidebar; @@ -18,6 +19,7 @@ use OCP\AppFramework\Controller; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; +use OCP\AppFramework\Http\ContentSecurityPolicy; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\TemplateResponse; @@ -32,11 +34,11 @@ class PageController extends Controller { public function __construct( string $appName, IRequest $request, - private ?string $userId, - private IEventDispatcher $eventDispatcher, - private IAppConfig $appConfig, - private IInitialState $initialState, - private IURLGenerator $urlGenerator, + private readonly ?string $userId, + private readonly IEventDispatcher $eventDispatcher, + private readonly IAppConfig $appConfig, + private readonly IInitialState $initialState, + private readonly IURLGenerator $urlGenerator, ) { parent::__construct($appName, $request); } @@ -79,7 +81,7 @@ public function indexMyMap(int $myMapId, MyMapsService $service): TemplateRespon $this->eventDispatcher->dispatchTyped(new LoadViewer()); $params = ['user' => $this->userId]; - $this->initialState->provideInitialState('photos', $this->appConfig->getValueBool('photos', 'enabled', 'no') === 'yes'); + $this->initialState->provideInitialState('photos', $this->appConfig->getValueBool('photos', 'enabled')); $response = new TemplateResponse('maps', 'main', $params); $this->addCsp($response); @@ -94,7 +96,7 @@ public function openGeoLink(string $url): TemplateResponse { } private function addCsp(Response $response): void { - $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); + $csp = new ContentSecurityPolicy(); // map tiles $csp->addAllowedImageDomain('https://*.tile.openstreetmap.org'); $csp->addAllowedImageDomain('https://tile.openstreetmap.org'); @@ -121,8 +123,8 @@ private function addCsp(Response $response): void { 'osrmFootURL', 'graphhopperURL', 'maplibreStreetStyleURL', - 'maplibreStreetStyleAuth' - 'maplibreStreetStylePmtiles' + 'maplibreStreetStyleAuth', + 'maplibreStreetStylePmtiles', ]; foreach ($urlKeys as $key) { $url = $this->appConfig->getValueString('maps', $key); @@ -134,15 +136,18 @@ private function addCsp(Response $response): void { if ($port && $port !== '') { $cleanUrl .= ':' . $port; } + $csp->addAllowedConnectDomain($cleanUrl); } } + //$csp->addAllowedConnectDomain('http://192.168.0.66:5000'); // poi images $csp->addAllowedImageDomain('https://nominatim.openstreetmap.org'); // search and geocoder $csp->addAllowedConnectDomain('https://nominatim.openstreetmap.org'); + $response->setContentSecurityPolicy($csp); } } diff --git a/lib/Controller/PhotosController.php b/lib/Controller/PhotosController.php index d177e67c5..fb628760f 100644 --- a/lib/Controller/PhotosController.php +++ b/lib/Controller/PhotosController.php @@ -1,5 +1,7 @@ * @copyright Piotr Bator 2017 */ - namespace OCA\Maps\Controller; use OC\User\NoUserException; @@ -32,10 +33,10 @@ class PhotosController extends Controller { public function __construct( string $appName, IRequest $request, - private GeophotoService $geophotoService, - private PhotofilesService $photofilesService, - private IRootFolder $root, - private string $userId, + private readonly GeophotoService $geophotoService, + private readonly PhotofilesService $photofilesService, + private readonly IRootFolder $root, + private readonly string $userId, ) { parent::__construct($appName, $request); } @@ -56,18 +57,11 @@ public function getPhotos(?int $myMapId = null, bool $respectNoMediaAndNoimage = $folder = $userFolder->getFirstNodeById($myMapId); $result = $this->geophotoService->getAll($this->userId, $folder, $respectNoMediaAndNoimage, $hideImagesOnCustomMaps, $hideImagesInMapsFolder); } + return new DataResponse($result); } /** - * @param int|null $myMapId - * @param string|null $timezone - * @param int $limit - * @param int $offset - * @param null $respectNoMediaAndNoimage - * @param null $hideImagesOnCustomMaps - * @param null $hideImagesInMapsFolder - * @return DataResponse * @throws Exception * @throws NoUserException * @throws NotFoundException @@ -84,8 +78,10 @@ public function getNonLocalizedPhotos(?int $myMapId = null, ?string $timezone = if (!$folder instanceof Folder) { throw new NotFoundException('Could find map with mapid: ' . $myMapId); } + $result = $this->geophotoService->getNonLocalized($this->userId, $folder, $respectNoMediaAndNoimage ?? true, $hideImagesOnCustomMaps ?? false, $hideImagesInMapsFolder ?? false, $timezone, $limit, $offset); } + return new DataResponse($result); } @@ -94,8 +90,6 @@ public function getNonLocalizedPhotos(?int $myMapId = null, ?string $timezone = * @param $paths * @param $lats * @param $lngs - * @param bool $relative - * @return DataResponse * @throws NoUserException * @throws NotFoundException * @throws NotPermittedException @@ -133,6 +127,7 @@ public function placePhotos($paths, $lats, $lngs, bool $directory = false, ?int } } } + $result = $this->photofilesService->setPhotosFilesCoords($this->userId, $paths, $lats, $lngs, $directory); return new DataResponse($result); } @@ -144,9 +139,10 @@ public function placePhotos($paths, $lats, $lngs, bool $directory = false, ?int public function resetPhotosCoords($paths, ?int $myMapId = null): DataResponse { $userFolder = $this->root->getUserFolder($this->userId); $result = []; - if (sizeof($paths) > 0) { + if (count($paths) > 0) { $result = $this->photofilesService->resetPhotosFilesCoords($this->userId, $paths); } + if (!is_null($myMapId)) { foreach ($paths as $key => $path) { $folder = $userFolder->getFirstNodeById($myMapId); @@ -157,6 +153,7 @@ public function resetPhotosCoords($paths, ?int $myMapId = null): DataResponse { } } } + return new DataResponse($result); } @@ -165,9 +162,9 @@ public function clearCache(): DataResponse { $result = $this->geophotoService->clearCache(); if ($result) { return new DataResponse('Cache cleared'); - } else { - return new DataResponse('Failed to clear Cache', 400); } + + return new DataResponse('Failed to clear Cache', 400); } #[NoAdminRequired] diff --git a/lib/Controller/PublicContactsController.php b/lib/Controller/PublicContactsController.php index 046b42c42..7cd6234ce 100644 --- a/lib/Controller/PublicContactsController.php +++ b/lib/Controller/PublicContactsController.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; use OCA\Maps\Service\AddressService; @@ -29,6 +30,7 @@ use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IManager as ShareManager; use OCP\Share\IShare; +use Sabre\VObject\Document; use Sabre\VObject\Reader; class PublicContactsController extends PublicPageController { @@ -42,8 +44,8 @@ public function __construct( IInitialStateService $initialStateService, ShareManager $shareManager, IUserManager $userManager, - private AddressService $addressService, - private IAvatarManager $avatarManager, + private readonly AddressService $addressService, + private readonly IAvatarManager $avatarManager, ) { parent::__construct($appName, $request, $session, $urlGenerator, $eventDispatcher, $appConfig, $initialStateService, $shareManager, $userManager); } @@ -75,7 +77,7 @@ private function getShare() { // Check whether share exists try { $share = $this->shareManager->getShareByToken($this->getToken()); - } catch (ShareNotFound $e) { + } catch (ShareNotFound) { // The share does not exists, we do not emit an ShareLinkAccessedEvent throw new NotFoundException(); } @@ -83,6 +85,7 @@ private function getShare() { if (!$this->validateShare($share)) { throw new NotFoundException(); } + return $share; } @@ -101,7 +104,6 @@ private function getShareNode() { /** * @PublicPage * - * @return DataResponse * @throws NotFoundException * @throws NotPermittedException * @throws \OCP\Files\InvalidPathException @@ -126,12 +128,13 @@ public function getContacts(): DataResponse { $result[] = $this->vCardToArray($permissions, $file, $vcard, $geo->getValue()); } elseif (is_countable($geo) && count($geo) > 0 && is_iterable($geo)) { foreach ($geo as $g) { - if (strlen($g->getValue()) > 1) { + if (strlen((string)$g->getValue()) > 1) { $result[] = $this->vCardToArray($permissions, $file, $vcard, $g->getValue()); } } } } + if (isset($vcard->ADR) && count($vcard->ADR) > 0) { foreach ($vcard->ADR as $adr) { $geo = $this->addressService->addressToGeo($adr->getValue(), $file->getId()); @@ -140,32 +143,27 @@ public function getContacts(): DataResponse { if (isset($adr->parameters()['TYPE'])) { $adrtype = $adr->parameters()['TYPE']->getValue(); } - if (is_string($geo) && strlen($geo) > 1) { + + if (strlen($geo) > 1) { $result[] = $this->vCardToArray($permissions, $file, $vcard, $geo, $adrtype, $adr->getValue(), $file->getId()); } } } } } + return new DataResponse($result); - } else { - throw new NotPermittedException(); } + + throw new NotPermittedException(); } /** - * @param int $sharePermissions - * @param Node $file - * @param \Sabre\VObject\Document $vcard - * @param string $geo - * @param string|null $adrtype - * @param string|null $adr - * @param int|null $fileId - * @return array * @throws NotFoundException * @throws \OCP\Files\InvalidPathException + * @return array */ - private function vCardToArray(int $sharePermissions, Node $file, \Sabre\VObject\Document $vcard, string $geo, ?string $adrtype = null, ?string $adr = null, ?int $fileId = null): array { + private function vCardToArray(int $sharePermissions, Node $file, Document $vcard, string $geo, ?string $adrtype = null, ?string $adr = null, ?int $fileId = null): array { $FNArray = $vcard->FN ? $vcard->FN->getJsonValue() : []; $fn = array_shift($FNArray); $NArray = $vcard->N ? $vcard->N->getJsonValue() : []; @@ -178,15 +176,12 @@ private function vCardToArray(int $sharePermissions, Node $file, \Sabre\VObject\ } } + $UIDArray = $vcard->UID->getJsonValue(); $uid = array_shift($UIDArray); $groups = $vcard->CATEGORIES; - if (!is_null($groups)) { - $groups = $groups->getValue(); - } else { - $groups = ''; - } - $result = [ + $groups = is_null($groups) ? '' : $groups->getValue(); + return [ 'FN' => $fn ?? $n ?? '???', 'UID' => $uid, 'HAS_PHOTO' => (isset($vcard->PHOTO) && $vcard->PHOTO !== null), @@ -200,24 +195,19 @@ private function vCardToArray(int $sharePermissions, Node $file, \Sabre\VObject\ 'isDeletable' => $file->isDeletable() && ($sharePermissions & (1 << 1)), 'isUpdateable' => $file->isUpdateable() && ($sharePermissions & (1 << 3)), ]; - return $result; } - /** - * @param string $n - * @return string|null - */ private function N2FN(string $n): ?string { - if ($n) { + if ($n !== '' && $n !== '0') { $spl = explode($n, ';'); if (count($spl) >= 4) { return $spl[3] . ' ' . $spl[1] . ' ' . $spl[0]; - } else { - return null; } - } else { + return null; } + + return null; } @@ -225,8 +215,6 @@ private function N2FN(string $n): ?string { * @PublicPage * @NoCSRFRequired * - * @param string $name - * @return DataDisplayResponse * @throws NotFoundException * @throws NotPermittedException */ diff --git a/lib/Controller/PublicFavoritePageController.php b/lib/Controller/PublicFavoritePageController.php index eb27fa55a..7cc659be2 100644 --- a/lib/Controller/PublicFavoritePageController.php +++ b/lib/Controller/PublicFavoritePageController.php @@ -1,5 +1,7 @@ * @@ -21,7 +23,6 @@ * along with this program. If not, see . * */ - namespace OCA\Maps\Controller; use OCA\Maps\DB\FavoriteShareMapper; @@ -36,24 +37,21 @@ use OCP\IRequest; use OCP\ISession; use OCP\IUserManager; +use OCP\Server; use OCP\Util; class PublicFavoritePageController extends PublicShareController { private $config; - /* @var FavoriteShareMapper */ - private $favoriteShareMapper; - public function __construct( - $appName, + string $appName, IRequest $request, ISession $session, IConfig $config, - FavoriteShareMapper $favoriteShareMapper, + private readonly FavoriteShareMapper $favoriteShareMapper, ) { parent::__construct($appName, $request, $session); $this->config = $config; - $this->favoriteShareMapper = $favoriteShareMapper; } /** @@ -71,9 +69,9 @@ public function sharedFavoritesCategory($token) { try { $share = $this->favoriteShareMapper->findByToken($token); - } catch (DoesNotExistException $e) { + } catch (DoesNotExistException) { return new DataResponse([], Http::STATUS_NOT_FOUND); - } catch (MultipleObjectsReturnedException $e) { + } catch (MultipleObjectsReturnedException) { return new DataResponse([], Http::STATUS_INTERNAL_SERVER_ERROR); } @@ -82,7 +80,7 @@ public function sharedFavoritesCategory($token) { $response = new PublicTemplateResponse('maps', 'public/favorites_index', []); - $ownerName = \OCP\Server::get(IUserManager::class)->get($share->getOwner())->getDisplayName(); + $ownerName = Server::get(IUserManager::class)->get($share->getOwner())->getDisplayName(); $response->setHeaderTitle($share->getCategory()); $response->setHeaderDetails('shared by ' . $ownerName); @@ -109,13 +107,12 @@ protected function getPasswordHash(): string { * * This function is already called from the middleware directly after setting the token. * - * @return bool * @since 14.0.0 */ public function isValidToken(): bool { try { $this->favoriteShareMapper->findByToken($this->getToken()); - } catch (DoesNotExistException|MultipleObjectsReturnedException $e) { + } catch (DoesNotExistException|MultipleObjectsReturnedException) { return false; } @@ -125,7 +122,6 @@ public function isValidToken(): bool { /** * Is a share with this token password protected * - * @return bool * @since 14.0.0 */ protected function isPasswordProtected(): bool { @@ -134,7 +130,6 @@ protected function isPasswordProtected(): bool { /** * @param $response - * @return void */ private function addCsp($response): void { if (class_exists('OCP\AppFramework\Http\ContentSecurityPolicy')) { @@ -163,16 +158,18 @@ private function addCsp($response): void { foreach ($urlKeys as $key) { $url = $this->config->getAppValue('maps', $key); if ($url !== '') { - $scheme = parse_url($url, PHP_URL_SCHEME); - $host = parse_url($url, PHP_URL_HOST); - $port = parse_url($url, PHP_URL_PORT); + $scheme = parse_url((string)$url, PHP_URL_SCHEME); + $host = parse_url((string)$url, PHP_URL_HOST); + $port = parse_url((string)$url, PHP_URL_PORT); $cleanUrl = $scheme . '://' . $host; if ($port && $port !== '') { $cleanUrl .= ':' . $port; } + $csp->addAllowedConnectDomain($cleanUrl); } } + //$csp->addAllowedConnectDomain('http://192.168.0.66:5000'); // poi images diff --git a/lib/Controller/PublicFavoritesApiController.php b/lib/Controller/PublicFavoritesApiController.php index f253256e3..9d81e4c8e 100644 --- a/lib/Controller/PublicFavoritesApiController.php +++ b/lib/Controller/PublicFavoritesApiController.php @@ -1,5 +1,7 @@ * @@ -21,8 +23,6 @@ * along with this program. If not, see . * */ - - namespace OCA\Maps\Controller; use OCA\Maps\DB\FavoriteShareMapper; @@ -41,8 +41,8 @@ public function __construct( $appName, IRequest $request, ISession $session, - private FavoritesService $favoritesService, - private FavoriteShareMapper $favoriteShareMapper, + private readonly FavoritesService $favoritesService, + private readonly FavoriteShareMapper $favoriteShareMapper, ) { parent::__construct($appName, $request, $session); } @@ -58,7 +58,7 @@ protected function isPasswordProtected(): bool { public function isValidToken(): bool { try { $this->favoriteShareMapper->findByToken($this->getToken()); - } catch (DoesNotExistException|MultipleObjectsReturnedException $e) { + } catch (DoesNotExistException|MultipleObjectsReturnedException) { return false; } diff --git a/lib/Controller/PublicFavoritesController.php b/lib/Controller/PublicFavoritesController.php index fb355bde7..a9add97a9 100644 --- a/lib/Controller/PublicFavoritesController.php +++ b/lib/Controller/PublicFavoritesController.php @@ -1,5 +1,7 @@ shareManager->getShareByToken($this->getToken()); - } catch (ShareNotFound $e) { + } catch (ShareNotFound) { // The share does not exists, we do not emit an ShareLinkAccessedEvent throw new NotFoundException(); } @@ -94,6 +95,7 @@ private function getShare(): IShare { if (!$this->validateShare($share)) { throw new NotFoundException(); } + return $share; } @@ -115,7 +117,7 @@ private function getShareNode() { private function getJSONFavoritesFile(Folder $folder, bool $isCreatable): Node { try { $file = $folder->get('.favorites.json'); - } catch (NotFoundException $e) { + } catch (NotFoundException) { if ($isCreatable) { $file = $folder->newFile('.favorites.json', $content = $this->defaultFavoritsJSON); } else { @@ -123,6 +125,7 @@ private function getJSONFavoritesFile(Folder $folder, bool $isCreatable): Node { } } + return $file; } @@ -141,7 +144,7 @@ public function getFavorites(): DataResponse { $isReadable = (bool)($permissions & (1 << 0)); if ($isReadable) { $favorites = $this->favoritesService->getFavoritesFromJSON($file); - $favorites = array_map(function ($favorite) use ($permissions) { + $favorites = array_map(function (array $favorite) use ($permissions): array { $favorite['isCreatable'] = ($permissions & (1 << 2)) && $favorite['isCreatable']; $favorite['isUpdateable'] = ($permissions & (1 << 1)) && $favorite['isUpdateable']; $favorite['isDeletable'] = ($permissions & (1 << 3)) && $favorite['isDeletable']; @@ -150,6 +153,7 @@ public function getFavorites(): DataResponse { } else { throw new NotPermittedException(); } + return new DataResponse($favorites); } @@ -160,7 +164,7 @@ public function getFavorites(): DataResponse { */ #[PublicPage] public function addFavorite(?string $name, float $lat, float $lng, ?string $category, ?string $comment, ?string $extensions): DataResponse { - if (is_numeric($lat) && is_numeric($lng)) { + if (is_numeric($lng)) { $share = $this->getShare(); $permissions = $share->getPermissions(); $folder = $this->getShareNode(); @@ -174,10 +178,11 @@ public function addFavorite(?string $name, float $lat, float $lng, ?string $cate } else { throw new NotPermittedException(); } + return new DataResponse($favorite); - } else { - return new DataResponse($this->l->t('Invalid values'), 400); } + + return new DataResponse($this->l->t('Invalid values'), 400); } /** @@ -201,11 +206,12 @@ public function addFavorites(array $favorites): DataResponse { $favorite['isDeletable'] = ($permissions & (1 << 3)) && $favorite['isDeletable']; $favoritesAfter[] = $favorite; } - }; + } + ; return new DataResponse($favoritesAfter); - } else { - throw new NotPermittedException(); } + + throw new NotPermittedException(); } /** @@ -224,10 +230,12 @@ public function editFavorite(int $id, ?string $name, ?float $lat, ?float $lng, ? if (!$isUpdateable) { throw new NotPermittedException(); } + $favorite = $this->favoritesService->getFavoriteFromJSON($file, $id); if ($favorite === null) { return new DataResponse($this->l->t('no such favorite'), 400); } + $this->favoritesService->editFavoriteInJSON($file, $id, $name, $lat, $lng, $category, $comment, $extensions); $editedFavorite = $this->favoritesService->getFavoriteFromJSON($file, $id); $editedFavorite['isDeletable'] = ($permissions & (1 << 3)) && $editedFavorite['isDeletable']; @@ -254,6 +262,7 @@ public function renameCategories(array $categories, string $newName): DataRespon } else { throw new NotPermittedException(); } + return new DataResponse('RENAMED'); } @@ -274,15 +283,15 @@ public function deleteFavorite(int $id): DataResponse { if ($this->favoritesService->deleteFavoriteFromJSON($file, $id) > 0) { return new DataResponse('DELETED'); } + return new DataResponse($this->l->t('no such favorite'), 400); - } else { - throw new NotPermittedException(); } + throw new NotPermittedException(); + } /** - * @param array $ids * @throws NotFoundException * @throws NotPermittedException * @throws \OCP\Files\InvalidPathException @@ -300,6 +309,7 @@ public function deleteFavorites(array $ids): DataResponse { } else { throw new NotPermittedException(); } + return new DataResponse('DELETED'); } @@ -314,11 +324,12 @@ public function getSharedCategories(): DataResponse { $folder = $this->getShareNode(); $isCreatable = ($permissions & (1 << 2)) && $folder->isCreatable(); $isReadable = ($permissions & (1 << 0)); - if ($isReadable) { + if ($isReadable !== 0) { $categories = $this->favoriteShareMapper->findAllByFolder($folder, $isCreatable); } else { throw new NotPermittedException(); } + return new DataResponse($categories); } } diff --git a/lib/Controller/PublicPageController.php b/lib/Controller/PublicPageController.php index fa78b49fb..8a82502ee 100644 --- a/lib/Controller/PublicPageController.php +++ b/lib/Controller/PublicPageController.php @@ -1,5 +1,7 @@ * @copyright Vinzenz Rosenkranz 2017 */ - namespace OCA\Maps\Controller; use OC\Security\CSP\ContentSecurityPolicy; @@ -52,7 +53,7 @@ public function __construct( public function isValidToken(): bool { try { $this->share = $this->shareManager->getShareByToken($this->getToken()); - } catch (ShareNotFound $e) { + } catch (ShareNotFound) { return false; } @@ -99,7 +100,7 @@ private function getShareNode(): Node { // Check whether share exists try { $share = $this->shareManager->getShareByToken($this->getToken()); - } catch (ShareNotFound $e) { + } catch (ShareNotFound) { // The share does not exists, we do not emit an ShareLinkAccessedEvent throw new NotFoundException(); } @@ -116,7 +117,7 @@ private function getShareNode(): Node { * @NoCSRFRequired */ public function showShare(): PublicTemplateResponse { - $shareNode = $this->getShareNode(); + $this->getShareNode(); $this->eventDispatcher->dispatchTyped(new LoadSidebar()); $this->eventDispatcher->dispatchTyped(new LoadViewer()); @@ -231,6 +232,7 @@ private function addCsp(Response $response): void { if ($port && $port !== '') { $cleanUrl .= ':' . $port; } + $csp->addAllowedConnectDomain($cleanUrl); } } @@ -239,6 +241,7 @@ private function addCsp(Response $response): void { $csp->addAllowedImageDomain('https://nominatim.openstreetmap.org'); // search and geocoder $csp->addAllowedConnectDomain('https://nominatim.openstreetmap.org'); + $response->setContentSecurityPolicy($csp); } } diff --git a/lib/Controller/PublicPhotosController.php b/lib/Controller/PublicPhotosController.php index 37a801f12..d1d784f58 100644 --- a/lib/Controller/PublicPhotosController.php +++ b/lib/Controller/PublicPhotosController.php @@ -1,5 +1,7 @@ * @copyright Piotr Bator 2017 */ - namespace OCA\Maps\Controller; +use OC\User\NoUserException; use OCA\Maps\Service\GeophotoService; use OCA\Maps\Service\PhotofilesService; use OCP\AppFramework\Http\DataResponse; @@ -20,7 +22,6 @@ use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OCP\IAppConfig; - use OCP\IInitialStateService; use OCP\IRequest; use OCP\ISession; @@ -28,6 +29,7 @@ use OCP\IUserManager; use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IManager as ShareManager; +use OCP\Share\IShare; class PublicPhotosController extends PublicPageController { @@ -53,7 +55,7 @@ public function __construct( * * @return bool */ - private function validateShare(\OCP\Share\IShare $share) { + private function validateShare(IShare $share) { // If the owner is disabled no access to the link is granted $owner = $this->userManager->get($share->getShareOwner()); if ($owner === null || !$owner->isEnabled()) { @@ -77,7 +79,7 @@ private function getShare() { // Check whether share exists try { $share = $this->shareManager->getShareByToken($this->getToken()); - } catch (ShareNotFound $e) { + } catch (ShareNotFound) { // The share does not exists, we do not emit an ShareLinkAccessedEvent throw new NotFoundException(); } @@ -85,6 +87,7 @@ private function getShare() { if (!$this->validateShare($share)) { throw new NotFoundException(); } + return $share; } @@ -102,10 +105,9 @@ private function getShareNode() { /** * @PublicPage - * @return DataResponse * @throws NotFoundException * @throws \OCP\Files\NotPermittedException - * @throws \OC\User\NoUserException + * @throws NoUserException */ public function getPhotos(): DataResponse { $share = $this->getShare(); @@ -116,7 +118,7 @@ public function getPhotos(): DataResponse { $owner = $share->getShareOwner(); $pre_path = $this->root->getUserFolder($owner)->getPath(); $result = $this->geophotoService->getAll($owner, $folder, true, false, false); - $photos = array_map(function ($photo) use ($folder, $permissions, $pre_path) { + $photos = array_map(function (array $photo) use ($folder, $permissions, $pre_path): \stdClass { $photo_object = (object)$photo; $photo_object->isCreatable = ($permissions & (1 << 2)) && $photo['isCreatable']; $photo_object->isUpdateable = ($permissions & (1 << 1)) && $photo['isUpdateable']; @@ -134,11 +136,10 @@ public function getPhotos(): DataResponse { /** * @PublicPage - * @return DataResponse * @throws NotFoundException * @throws NotPermittedException * @throws \OCP\Files\InvalidPathException - * @throws \OC\User\NoUserException + * @throws NoUserException */ public function getNonLocalizedPhotos(?string $timezone = null, int $limit = 250, int $offset = 0): DataResponse { $share = $this->getShare(); @@ -149,7 +150,7 @@ public function getNonLocalizedPhotos(?string $timezone = null, int $limit = 250 $owner = $share->getShareOwner(); $pre_path = $this->root->getUserFolder($owner)->getPath(); $result = $this->geophotoService->getNonLocalized($owner, $folder, true, false, false, $timezone, $limit, $offset); - $photos = array_map(function ($photo) use ($folder, $permissions, $pre_path) { + $photos = array_map(function (array $photo) use ($folder, $permissions, $pre_path): \stdClass { $photo_object = (object)$photo; $photo_object->isCreatable = ($permissions & (1 << 2)) && $photo['isCreatable']; $photo_object->isUpdateable = ($permissions & (1 << 1)) && $photo['isUpdateable']; @@ -167,15 +168,14 @@ public function getNonLocalizedPhotos(?string $timezone = null, int $limit = 250 /** * @PublicPage - * @return DataResponse */ public function clearCache(): DataResponse { $result = $this->geophotoService->clearCache(); if ($result) { return new DataResponse('Cache cleared'); - } else { - return new DataResponse('Failed to clear Cache', 400); } + + return new DataResponse('Failed to clear Cache', 400); } } diff --git a/lib/Controller/PublicTracksController.php b/lib/Controller/PublicTracksController.php index aac7f2e93..2a25199bc 100644 --- a/lib/Controller/PublicTracksController.php +++ b/lib/Controller/PublicTracksController.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; +use OC\User\NoUserException; use OCA\Maps\Service\TracksService; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\PublicPage; @@ -83,7 +85,7 @@ private function getShare(): IShare { // Check whether share exists try { $share = $this->shareManager->getShareByToken($this->getToken()); - } catch (ShareNotFound $e) { + } catch (ShareNotFound) { // The share does not exists, we do not emit an ShareLinkAccessedEvent throw new NotFoundException(); } @@ -91,6 +93,7 @@ private function getShare(): IShare { if (!$this->validateShare($share)) { throw new NotFoundException(); } + return $share; } @@ -108,7 +111,7 @@ private function getShareNode(): Node { /** * @throws NotFoundException * @throws NotPermittedException - * @throws \OC\User\NoUserException + * @throws NoUserException */ #[PublicPage] public function getTracks(): DataResponse { @@ -124,7 +127,7 @@ public function getTracks(): DataResponse { $owner = $share->getShareOwner(); $pre_path = $this->root->getUserFolder($owner)->getPath(); $tracks = $this->tracksService->getTracksFromDB($owner, $folder, true, false, false); - $newTracks = array_map(function ($track) use ($folder, $permissions, $pre_path, $hideDownload): array { + $newTracks = array_map(function (array $track) use ($folder, $permissions, $pre_path, $hideDownload): array { $track['isCreatable'] = ($permissions & (1 << 2)) && $track['isCreatable']; $track['isUpdateable'] = ($permissions & (1 << 1)) && $track['isUpdateable']; $track['isDeletable'] = ($permissions & (1 << 3)) && $track['isDeletable']; @@ -150,6 +153,7 @@ public function getTrackContentByFileId(int $id): DataResponse { if (!$isReadable || !($folder instanceof Folder)) { throw new NotPermittedException(); } + $owner = $share->getShareOwner(); $track = $this->tracksService->getTrackByFileIDFromDB($id, $owner); $trackFile = is_null($track) ? null : $folder->getFirstNodeById($track['file_id']); @@ -166,6 +170,7 @@ public function getTrackContentByFileId(int $id): DataResponse { } else { $metadata = $track['metadata']; } + return new DataResponse([ 'metadata' => $metadata, 'content' => $trackContent @@ -173,7 +178,6 @@ public function getTrackContentByFileId(int $id): DataResponse { } /** - * @return DataResponse * @throws NotFoundException * @throws \OCP\Files\InvalidPathException */ @@ -199,6 +203,7 @@ public function getTrackFileContent(int $id): DataResponse { } else { $metadata = $track['metadata']; } + return new DataResponse([ 'metadata' => $metadata, 'content' => $trackContent @@ -223,9 +228,9 @@ public function editTrack(int $id, string $color, string $metadata, string $etag if ($track !== null) { $this->tracksService->editTrackInDB($id, $color, $metadata, $etag); return new DataResponse('EDITED'); - } else { - return new DataResponse($this->l->t('No such track'), 400); } + + return new DataResponse($this->l->t('No such track'), 400); } #[NoAdminRequired] @@ -240,11 +245,11 @@ public function deleteTrack(int $id): DataResponse { if ($track !== null) { $this->tracksService->deleteTrackFromDB($id); return new DataResponse('DELETED'); - } else { - return new DataResponse($this->l->t('No such track'), 400); } - } else { - throw new NotPermittedException(); + + return new DataResponse($this->l->t('No such track'), 400); } + + throw new NotPermittedException(); } } diff --git a/lib/Controller/PublicUtilsController.php b/lib/Controller/PublicUtilsController.php index eacf5b492..b894f3938 100644 --- a/lib/Controller/PublicUtilsController.php +++ b/lib/Controller/PublicUtilsController.php @@ -1,5 +1,7 @@ 2023 */ - namespace OCA\Maps\Controller; use OCP\AppFramework\Http\Attribute\PublicPage; @@ -30,6 +31,7 @@ use OCP\Lock\LockedException; use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IManager as ShareManager; +use OCP\Share\IShare; class PublicUtilsController extends PublicPageController { public function __construct( @@ -52,7 +54,7 @@ public function __construct( * * @return bool */ - private function validateShare(\OCP\Share\IShare $share) { + private function validateShare(IShare $share) { // If the owner is disabled no access to the link is granted $owner = $this->userManager->get($share->getShareOwner()); if ($owner === null || !$owner->isEnabled()) { @@ -76,7 +78,7 @@ private function getShare() { // Check whether share exists try { $share = $this->shareManager->getShareByToken($this->getToken()); - } catch (ShareNotFound $e) { + } catch (ShareNotFound) { // The share does not exists, we do not emit an ShareLinkAccessedEvent throw new NotFoundException(); } @@ -84,6 +86,7 @@ private function getShare() { if (!$this->validateShare($share)) { throw new NotFoundException(); } + return $share; } @@ -103,8 +106,6 @@ private function getShareNode() { * Save options values to the DB for current user * * @param $options - * @param null $myMapId - * @return DataResponse * @throws NotFoundException * @throws GenericFileException * @throws InvalidPathException @@ -119,27 +120,30 @@ public function saveOptionValue($options, $myMapId = null): DataResponse { try { $file = $folder->get('.index.maps'); - } catch (NotFoundException $e) { + } catch (NotFoundException) { if ($isCreatable) { $file = $folder->newFile('.index.maps', $content = '{}'); } else { throw new NotFoundException(); } } + $isUpdateable = ($permissions & (1 << 1)) && $file->isUpdateable(); if (!$isUpdateable) { throw new NotPermittedException(); } try { - $ov = json_decode($file->getContent(), true, 512); + $ov = json_decode((string)$file->getContent(), true, 512); foreach ($options as $key => $value) { $ov[$key] = $value; } + $file->putContent(json_encode($ov, JSON_PRETTY_PRINT)); - } catch (LockedException $e) { + } catch (LockedException) { return new DataResponse('File is locked', 500); } + return new DataResponse(['done' => 1]); } @@ -161,14 +165,15 @@ public function getOptionsValues(): DataResponse { $isCreatable = ($permissions & (1 << 2)) && $folder->isCreatable(); try { $file = $folder->get('.index.maps'); - } catch (NotFoundException $e) { + } catch (NotFoundException) { if ($isCreatable) { $file = $folder->newFile('.index.maps', $content = '{}'); } else { throw new NotFoundException(); } } - $ov = json_decode($file->getContent(), true, 512); + + $ov = json_decode((string)$file->getContent(), true, 512); // Maps content can be read mostly from the folder $ov['isReadable'] = ($permissions & (1 << 0)) && $folder->isReadable(); @@ -198,6 +203,7 @@ public function getOptionsValues(): DataResponse { $v = $this->appConfig->getValueString('maps', $k); $ov[$k] = $v; } + return new DataResponse(['values' => $ov]); } @@ -205,8 +211,6 @@ public function getOptionsValues(): DataResponse { /** * get content of mapbox traffic style * @PublicPage - * - * @return DataResponse */ public function getTrafficStyle(): DataResponse { $style = [ diff --git a/lib/Controller/RoutingController.php b/lib/Controller/RoutingController.php index 9c108177c..1b9e61acc 100644 --- a/lib/Controller/RoutingController.php +++ b/lib/Controller/RoutingController.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; use OCA\Maps\Service\TracksService; @@ -18,27 +19,28 @@ use OCP\AppFramework\Http\DataResponse; use OCP\Files\Folder; use OCP\Files\IRootFolder; -use OCP\IConfig; +use OCP\IAppConfig; use OCP\IL10N; use OCP\IRequest; class RoutingController extends Controller { private ?Folder $userfolder = null; - private string $appVersion; + + private readonly string $appVersion; public function __construct( string $appName, IRequest $request, - IConfig $config, - private IL10N $l, - private TracksService $tracksService, + IAppConfig $appConfig, + private readonly IL10N $l, + private readonly TracksService $tracksService, IRootFolder $rootFolder, - private ?string $userId, + private readonly ?string $userId, ) { parent::__construct($appName, $request); - $this->appVersion = $config->getAppValue('maps', 'installed_version'); + $this->appVersion = $appConfig->getValueString('maps', 'installed_version'); // IConfig object - if ($this->userId !== '' and $this->userId !== null) { + if ($this->userId !== '' && $this->userId !== null) { // path of user files folder relative to DATA folder $this->userfolder = $rootFolder->getUserFolder($userId); } @@ -61,18 +63,18 @@ public function exportRoute($type, $coords, $name, $totDist, $totTime, $myMapId if (!$userFolder->nodeExists('/Maps')) { $userFolder->newFolder('Maps'); } + if ($userFolder->nodeExists('/Maps')) { $mapsFolder = $userFolder->get('/Maps'); if (!$mapsFolder instanceof Folder) { - $response = new DataResponse($this->l->t('/Maps is not a directory'), 400); - return $response; - } elseif (!$mapsFolder->isCreatable()) { - $response = new DataResponse($this->l->t('/Maps directory is not writeable'), 400); - return $response; + return new DataResponse($this->l->t('/Maps is not a directory'), 400); + } + + if (!$mapsFolder->isCreatable()) { + return new DataResponse($this->l->t('/Maps directory is not writeable'), 400); } } else { - $response = new DataResponse($this->l->t('Impossible to create /Maps directory'), 400); - return $response; + return new DataResponse($this->l->t('Impossible to create /Maps directory'), 400); } } else { $folder = $userFolder->getFirstNodeById($myMapId); @@ -85,9 +87,11 @@ public function exportRoute($type, $coords, $name, $totDist, $totTime, $myMapId if ($mapsFolder->nodeExists($filename)) { $mapsFolder->get($filename)->delete(); } + if ($mapsFolder->nodeExists($filename . '.tmp')) { $mapsFolder->get($filename . '.tmp')->delete(); } + $file = $mapsFolder->newFile($filename . 'tmp'); $fileHandler = $file->fopen('w'); @@ -109,6 +113,7 @@ public function exportRoute($type, $coords, $name, $totDist, $totTime, $myMapId $line = ' ' . "\n"; fwrite($fileHandler, $line); } + fwrite($fileHandler, ' ' . "\n"); } elseif ($type === 'track') { fwrite($fileHandler, ' ' . "\n"); @@ -118,13 +123,16 @@ public function exportRoute($type, $coords, $name, $totDist, $totTime, $myMapId $line = ' ' . "\n"; fwrite($fileHandler, $line); } + fwrite($fileHandler, ' ' . "\n"); fwrite($fileHandler, ' ' . "\n"); } + fwrite($fileHandler, '' . "\n"); fclose($fileHandler); $file->touch(); - $file->move(substr($file->getPath(), 0, -3)); + $file->move(substr((string)$file->getPath(), 0, -3)); + $track = $this->tracksService->getTrackByFileIDFromDB($file->getId(), $this->userId); return new DataResponse($track); } diff --git a/lib/Controller/TracksController.php b/lib/Controller/TracksController.php index 0d689ccb6..570b8e6c7 100644 --- a/lib/Controller/TracksController.php +++ b/lib/Controller/TracksController.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; use OCA\Maps\Service\TracksService; @@ -30,10 +31,10 @@ class TracksController extends Controller { public function __construct( string $appName, IRequest $request, - private IL10N $l, - private TracksService $tracksService, + private readonly IL10N $l, + private readonly TracksService $tracksService, IRootFolder $rootFolder, - private ?string $userId, + private readonly ?string $userId, ) { parent::__construct($appName, $request); if ($this->userId !== '' && $this->userId !== null) { @@ -54,6 +55,7 @@ public function getTracks(?int $myMapId = null): DataResponse { $folder = array_shift($folders); $tracks = $this->tracksService->getTracksFromDB($this->userId, $folder, true, false, false); } + return new DataResponse($tracks); } @@ -64,6 +66,7 @@ public function getTrackContentByFileId(int $id): DataResponse { if (!$trackFile instanceof File) { return new DataResponse($this->l->t('File not found'), 400); } + $trackContent = remove_utf8_bom($trackFile->getContent()); // compute metadata if necessary // first time we get it OR the file changed @@ -73,6 +76,7 @@ public function getTrackContentByFileId(int $id): DataResponse { } else { $metadata = $track['metadata']; } + return new DataResponse([ 'metadata' => $metadata, 'content' => $trackContent @@ -100,6 +104,7 @@ public function getTrackFileContent(int $id): DataResponse { } else { $metadata = $track['metadata']; } + return new DataResponse([ 'metadata' => $metadata, 'content' => $trackContent @@ -112,9 +117,9 @@ public function editTrack(int $id, ?string $color, ?string $metadata, ?string $e if ($track !== null) { $this->tracksService->editTrackInDB($id, $color, $metadata, $etag); return new DataResponse('EDITED'); - } else { - return new DataResponse($this->l->t('No such track'), 400); } + + return new DataResponse($this->l->t('No such track'), 400); } #[NoAdminRequired] @@ -123,9 +128,9 @@ public function deleteTrack(int $id): DataResponse { if ($track !== null) { $this->tracksService->deleteTrackFromDB($id); return new DataResponse('DELETED'); - } else { - return new DataResponse($this->l->t('No such track'), 400); } + + return new DataResponse($this->l->t('No such track'), 400); } } diff --git a/lib/Controller/UtilsController.php b/lib/Controller/UtilsController.php index e7ce86c0d..c1bf02f69 100644 --- a/lib/Controller/UtilsController.php +++ b/lib/Controller/UtilsController.php @@ -1,5 +1,7 @@ 2023 */ - namespace OCA\Maps\Controller; use OCP\AppFramework\Controller; @@ -26,6 +27,7 @@ use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; +use OCP\IAppConfig; use OCP\IConfig; use OCP\IRequest; use OCP\Lock\LockedException; @@ -34,9 +36,10 @@ class UtilsController extends Controller { public function __construct( string $appName, IRequest $request, - private IConfig $config, - private IRootFolder $root, - private string $userId, + private readonly IAppConfig $appConfig, + private readonly IConfig $config, + private readonly IRootFolder $root, + private readonly string $userId, ) { parent::__construct($appName, $request); } @@ -45,12 +48,11 @@ public function __construct( * Save options values to the DB for current user * * @param $options - * @return DataResponse * @throws \OCP\PreConditionNotMetException */ #[NoAdminRequired] - public function saveOptionValue($options, $myMapId = null): DataResponse { - if (is_null($myMapId) || $myMapId === '') { + public function saveOptionValue($options, ?int $myMapId = null): DataResponse { + if (is_null($myMapId)) { foreach ($options as $key => $value) { $this->config->setUserValue($this->userId, 'maps', $key, $value); } @@ -60,22 +62,26 @@ public function saveOptionValue($options, $myMapId = null): DataResponse { if (!$folder instanceof Folder) { throw new NotFoundException('Could find map with mapid: ' . $myMapId); } + try { /** @var File $file */ $file = $folder->get('.index.maps'); - } catch (NotFoundException $e) { + } catch (NotFoundException) { $file = $folder->newFile('.index.maps', $content = '{}'); } + try { - $ov = json_decode($file->getContent(), true, 512); + $ov = json_decode((string)$file->getContent(), true, 512); foreach ($options as $key => $value) { $ov[$key] = $value; } + $file->putContent(json_encode($ov, JSON_PRETTY_PRINT)); - } catch (LockedException $e) { + } catch (LockedException) { return new DataResponse('File is locked', 500); } } + return new DataResponse(['done' => 1]); } @@ -93,6 +99,7 @@ public function getOptionsValues($myMapId = null): DataResponse { $value = $this->config->getUserValue($this->userId, 'maps', $key); $ov[$key] = $value; } + $ov['isCreatable'] = true; $ov['isDeletable'] = false; $ov['isReadable'] = true; @@ -104,13 +111,15 @@ public function getOptionsValues($myMapId = null): DataResponse { if (!$folder instanceof Folder) { throw new NotFoundException('Could find map with mapid: ' . $myMapId); } + try { /** @var File $file */ $file = $folder->get('.index.maps'); - } catch (NotFoundException $e) { + } catch (NotFoundException) { $file = $folder->newFile('.index.maps', $content = '{}'); } - $ov = json_decode($file->getContent(), true, 512); + + $ov = json_decode((string)$file->getContent(), true, 512); $ov['isCreatable'] = $folder->isCreatable(); //We can delete the map by deleting the folder or the .index.maps file $ov['isDeletable'] = $folder->isDeletable() || $file->isDeletable(); @@ -136,9 +145,10 @@ public function getOptionsValues($myMapId = null): DataResponse { 'graphhopperURL' ]; foreach ($settingsKeys as $k) { - $v = $this->config->getAppValue('maps', $k); + $v = $this->appConfig->getValueString('maps', $k); $ov[$k] = $v; } + return new DataResponse(['values' => $ov]); } @@ -146,7 +156,6 @@ public function getOptionsValues($myMapId = null): DataResponse { * set routing settings * * @param $values - * @return DataResponse */ public function setRoutingSettings($values): DataResponse { $acceptedKeys = [ @@ -163,9 +172,10 @@ public function setRoutingSettings($values): DataResponse { ]; foreach ($values as $k => $v) { if (in_array($k, $acceptedKeys)) { - $this->config->setAppValue('maps', $k, $v); + $this->appConfig->setValueString('maps', $k, $v); } } + $response = new DataResponse('DONE'); $csp = new ContentSecurityPolicy(); $csp->addAllowedImageDomain('*') diff --git a/lib/DB/DeviceShare.php b/lib/DB/DeviceShare.php index 207b370fe..6df1d2967 100644 --- a/lib/DB/DeviceShare.php +++ b/lib/DB/DeviceShare.php @@ -1,5 +1,7 @@ * @@ -21,7 +23,6 @@ * along with this program. If not, see . * */ - namespace OCA\Maps\DB; use OCP\AppFramework\Db\Entity; @@ -29,18 +30,21 @@ /** * @method string getToken() - * @method string getDeviceId() - * @method string getTimestampFrom() - * @method string getTimestampTo() - * @method string setToken(string $token) - * @method string setDeviceId(int $deviceId) - * @method string setTimestampFrom(int $timestampFrom) - * @method string setTimestampTo(int $timestampTo) + * @method int getDeviceId() + * @method int getTimestampFrom() + * @method int getTimestampTo() + * @method void setToken(string $token) + * @method void setDeviceId(int $deviceId) + * @method void setTimestampFrom(int $timestampFrom) + * @method void setTimestampTo(int $timestampTo) */ class DeviceShare extends Entity { public $token; + public $deviceId; + public $timestampFrom; + public $timestampTo; public function __construct() { diff --git a/lib/DB/DeviceShareMapper.php b/lib/DB/DeviceShareMapper.php index 340ff1bdb..9bd30aa6a 100644 --- a/lib/DB/DeviceShareMapper.php +++ b/lib/DB/DeviceShareMapper.php @@ -1,5 +1,7 @@ * @@ -21,7 +23,6 @@ * along with this program. If not, see . * */ - namespace OCA\Maps\DB; use OC\Share\Constants; @@ -31,7 +32,6 @@ use OCP\AppFramework\Db\QBMapper; use OCP\DB\Exception; use OCP\DB\QueryBuilder\IQueryBuilder; -use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\IDBConnection; use OCP\Security\ISecureRandom; @@ -40,13 +40,11 @@ class DeviceShareMapper extends QBMapper { /* @var ISecureRandom */ private $secureRandom; - private $root; - public function __construct(IDBConnection $db, ISecureRandom $secureRandom, IRootFolder $root) { + public function __construct(IDBConnection $db, ISecureRandom $secureRandom) { parent::__construct($db, 'maps_device_shares'); $this->secureRandom = $secureRandom; - $this->root = $root; } /** @@ -210,6 +208,7 @@ public function removeById($id) { } catch (DoesNotExistException) { return false; } + return true; } @@ -226,6 +225,7 @@ public function removeAllByDeviceId($deviceId) { } catch (DoesNotExistException) { return false; } + return true; } } diff --git a/lib/DB/FavoriteShare.php b/lib/DB/FavoriteShare.php index b07de4073..a63d376e2 100644 --- a/lib/DB/FavoriteShare.php +++ b/lib/DB/FavoriteShare.php @@ -1,5 +1,7 @@ * @@ -21,7 +23,6 @@ * along with this program. If not, see . * */ - namespace OCA\Maps\DB; use OCP\AppFramework\Db\Entity; @@ -38,8 +39,11 @@ */ class FavoriteShare extends Entity { public $owner; + public $token; + public $category; + public $allowEdits = false; public function __construct() { diff --git a/lib/DB/FavoriteShareMapper.php b/lib/DB/FavoriteShareMapper.php index b4d39a8d6..34d20b294 100644 --- a/lib/DB/FavoriteShareMapper.php +++ b/lib/DB/FavoriteShareMapper.php @@ -1,5 +1,7 @@ * @@ -21,10 +23,10 @@ * along with this program. If not, see . * */ - namespace OCA\Maps\DB; use OC\Share\Constants; +use OC\User\NoUserException; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\AppFramework\Db\QBMapper; @@ -40,8 +42,8 @@ class FavoriteShareMapper extends QBMapper { public function __construct( IDBConnection $db, - private ISecureRandom $secureRandom, - private IRootFolder $root, + private readonly ISecureRandom $secureRandom, + private readonly IRootFolder $root, ) { parent::__construct($db, 'maps_favorite_shares'); } @@ -93,7 +95,7 @@ public function findAllByOwner(string $owner): array { /** * @throws \OCP\Files\NotPermittedException - * @throws \OC\User\NoUserException + * @throws NoUserException */ public function findAllByMapId(string $userId, int $mapId): array { $userFolder = $this->root->getUserFolder($userId); @@ -102,6 +104,7 @@ public function findAllByMapId(string $userId, int $mapId): array { if (!$folder instanceof Folder) { return $shares; } + return $this->findAllByFolder($folder); } @@ -112,15 +115,16 @@ public function findAllByFolder(Folder $folder, bool $isCreatable = true): array try { /** @var File $file */ $file = $folder->get('.favorite_shares.json'); - } catch (NotFoundException $e) { + } catch (NotFoundException) { if ($isCreatable) { $folder->newFile('.favorite_shares.json', '[]'); return []; - } else { - throw new NotFoundException(); } + + throw new NotFoundException(); } - return json_decode($file->getContent(), true); + + return json_decode((string)$file->getContent(), true); } /** @@ -145,7 +149,7 @@ public function findByOwnerAndCategory(string $owner, string $category): Favorit * @param $category * @return mixed|null * @throws \OCP\Files\NotPermittedException - * @throws \OC\User\NoUserException + * @throws NoUserException */ public function findByMapIdAndCategory(string $userId, int $mapId, $category) { $shares = $this->findAllByMapId($userId, $mapId); @@ -154,6 +158,7 @@ public function findByMapIdAndCategory(string $userId, int $mapId, $category) { return $share; } } + return null; } @@ -165,12 +170,14 @@ public function removeByMapIdAndCategory(string $userId, int $mapId, $category) if (!$folder instanceof Folder) { return $deleted; } + try { $file = $folder->get('.favorite_shares.json'); - } catch (NotFoundException $e) { + } catch (NotFoundException) { $file = $folder->newFile('.favorite_shares.json', $content = '[]'); } - $data = json_decode($file->getContent(), true); + + $data = json_decode((string)$file->getContent(), true); foreach ($data as $share) { $c = $share['category']; if ($c === $category) { @@ -179,6 +186,7 @@ public function removeByMapIdAndCategory(string $userId, int $mapId, $category) $shares[] = $share; } } + $file->putContent(json_encode($shares, JSON_PRETTY_PRINT)); return $deleted; } @@ -189,9 +197,9 @@ public function findOrCreateByOwnerAndCategory(string $owner, string $category): try { $entity = $this->findByOwnerAndCategory($owner, $category); - } catch (DoesNotExistException $e) { + } catch (DoesNotExistException) { $entity = $this->create($owner, $category); - } catch (MultipleObjectsReturnedException $e) { + } catch (MultipleObjectsReturnedException) { } return $entity; @@ -200,7 +208,7 @@ public function findOrCreateByOwnerAndCategory(string $owner, string $category): public function removeByOwnerAndCategory(string $owner, string $category): bool { try { $entity = $this->findByOwnerAndCategory($owner, $category); - } catch (DoesNotExistException|MultipleObjectsReturnedException $e) { + } catch (DoesNotExistException|MultipleObjectsReturnedException) { return false; } diff --git a/lib/DB/Geophoto.php b/lib/DB/Geophoto.php index e2133738a..eff4758ed 100644 --- a/lib/DB/Geophoto.php +++ b/lib/DB/Geophoto.php @@ -1,5 +1,7 @@ * @copyright Piotr Bator 2017 */ - namespace OCA\Maps\DB; use OCP\AppFramework\Db\Entity; @@ -17,9 +18,13 @@ class Geophoto extends Entity { protected $fileId; + protected $lat; + protected $lng; + protected $dateTaken; + protected $userId; public function __construct() { diff --git a/lib/DB/GeophotoMapper.php b/lib/DB/GeophotoMapper.php index 372c4eef1..d7688bcfd 100644 --- a/lib/DB/GeophotoMapper.php +++ b/lib/DB/GeophotoMapper.php @@ -1,5 +1,7 @@ * @copyright Piotr Bator 2017 */ - namespace OCA\Maps\DB; use OCP\AppFramework\Db\QBMapper; @@ -105,9 +106,11 @@ public function findAll($userId, $limit = null, $offset = null) { if (!is_null($offset)) { $qb->setFirstResult($offset); } + if (!is_null($limit)) { $qb->setMaxResults($limit); } + return $this->findEntities($qb); } @@ -134,9 +137,11 @@ public function findAllNonLocalized($userId, $limit = null, $offset = null) { if (!is_null($offset)) { $qb->setFirstResult($offset); } + if (!is_null($limit)) { $qb->setMaxResults($limit); } + return array_reverse($this->findEntities($qb)); } diff --git a/lib/Helper/ExifDataInvalidException.php b/lib/Helper/ExifDataInvalidException.php index 67c12d921..4ee72acca 100644 --- a/lib/Helper/ExifDataInvalidException.php +++ b/lib/Helper/ExifDataInvalidException.php @@ -1,5 +1,7 @@ [0-9]{4})\:(?[0-9]{2})\:(?[0-9]{2}) (?[0-9]{2})\:(?[0-9]{2})\:(?[0-9]{2})'; + private const EXIF_TIME_REGEX = '(?\d{4})\:(?\d{2})\:(?\d{2}) (?\d{2})\:(?\d{2})\:(?\d{2})'; - /** - * @var int|null - */ - private $timestamp = null; + private ?int $timestamp = null; - /** - * @var float|null - */ - private $latitude = null; + private ?float $latitude = null; - /** - * @var float|null - */ - private $longitude = null; + private ?float $longitude = null; - /** - * @var bool|null - */ - private $is_valid = null; - - /** - * @var ?array - */ - protected $exif_data = null; + private ?bool $is_valid = null; /** * @throws PelInvalidArgumentException @@ -103,14 +77,18 @@ protected static function get_exif_data_array(string $path) : array { $data = @exif_read_data($path, null, true); if ($data && isset($data['EXIF']) && is_array($data['EXIF']) && isset($data['EXIF'][self::LATITUDE]) && isset($data['EXIF'][self::LONGITUDE])) { return $data['EXIF']; - } elseif ($data && isset($data['GPS']) && is_array($data['GPS']) && isset($data['GPS'][self::LATITUDE]) && isset($data['GPS'][self::LONGITUDE])) { + } + + if ($data && isset($data['GPS']) && is_array($data['GPS']) && isset($data['GPS'][self::LATITUDE]) && isset($data['GPS'][self::LONGITUDE])) { $d = $data['GPS']; if (!isset($d[self::TIMESTAMP]) && isset($data['EXIF'][self::TIMESTAMP])) { $d[self::TIMESTAMP] = $data['EXIF'][self::TIMESTAMP]; } + return $d; } } + $data = new PelDataWindow(file_get_contents($path)); if (PelJpeg::isValid($data)) { $pelJpeg = new PelJpeg($data); @@ -126,22 +104,27 @@ protected static function get_exif_data_array(string $path) : array { } else { return []; } + if (is_null($pelTiff)) { return []; } + $pelIfd0 = $pelTiff->getIfd(); if (is_null($pelIfd0)) { return []; } + $pelIfdExif = $pelIfd0->getSubIfd(PelIfd::EXIF); if (is_null($pelIfdExif)) { return []; } + $pelDateTimeOriginal = $pelIfdExif->getEntry(PelTag::DATE_TIME_ORIGINAL); if (is_null($pelDateTimeOriginal)) { return []; } + $exif = [ # self::TIMESTAMP => $pelDateTimeOriginal->getValue(PelEntryTime::EXIF_STRING) // for old pel 0.9.6 and above self::TIMESTAMP => (int)$pelDateTimeOriginal->getValue() // for new pel >= 0.9.11 @@ -159,21 +142,21 @@ protected static function get_exif_data_array(string $path) : array { $exif ); } + Pel::clearExceptions(); return $exif; } /** - * @param PelIfd $pelIfdGPS * @param $target * @param $source * @param $ref_target * @param $ref_source - * @param array $exif + * @param array $exif */ - protected static function readPelCoordinate(PelIfd $pelIfdGPS, $target, $source, $ref_target, $ref_source, array &$exif = []) : void { + protected static function readPelCoordinate(PelIfd $pelIfdGPS, $target, $source, string $ref_target, $ref_source, array &$exif = []) : void { $coordinate = $pelIfdGPS->getEntry($source)->getValue(); - if ((int)$coordinate[0][1] != 0 && (int)$coordinate[1][1] != 0 && (int)$coordinate[2][1] != 0) { + if ((int)$coordinate[0][1] !== 0 && (int)$coordinate[1][1] !== 0 && (int)$coordinate[2][1] !== 0) { $exif[$ref_target] = $pelIfdGPS->getEntry($ref_source)->getValue(); $exif[$target] = [ 0 => (int)$coordinate[0][0] / (int)$coordinate[0][1], @@ -184,24 +167,24 @@ protected static function readPelCoordinate(PelIfd $pelIfdGPS, $target, $source, } /** - * @param string $path * @return ExifGeoData */ public static function get(string $path) : ?ExifGeoData { try { $data = static::get_exif_data_array($path); - } catch (\Throwable $e) { + } catch (\Throwable) { $data = []; } + return new static($data); } /** * ExifGeoData constructor. - * @param array $exif_data */ - final private function __construct(array $exif_data) { - $this->exif_data = $exif_data; + final private function __construct( + protected array $exif_data, + ) { $this->parse(); } @@ -210,10 +193,11 @@ final private function __construct(array $exif_data) { * @throws ExifDataInvalidException * @throws ExifDataNoLocationException */ - public function validate($invalidate_zero_iland = false) { + public function validate($invalidate_zero_iland = false): void { if (!$this->exif_data) { throw new ExifDataInvalidException('No exif_data found', 1); } + if (!is_array($this->exif_data)) { throw new ExifDataInvalidException('exif_data is not an array', 2); } @@ -221,6 +205,7 @@ public function validate($invalidate_zero_iland = false) { if (!isset($this->exif_data[self::LATITUDE]) || !isset($this->exif_data[self::LONGITUDE])) { throw new ExifDataNoLocationException('Latitude and/or Longitude are missing from exif data', 1); } + if ($invalidate_zero_iland && $this->isZeroIsland()) { $this->latitude = null; $this->longitude = null; @@ -228,18 +213,16 @@ public function validate($invalidate_zero_iland = false) { } } - /** - * @return bool - */ public function isValid(): bool { if ($this->is_valid === null) { try { $this->validate(); $this->is_valid = true; - } catch (\Throwable $e) { + } catch (\Throwable) { $this->is_valid = false; } } + return $this->is_valid; } @@ -249,11 +232,13 @@ private function parse(): void { if (isset($this->exif_data[self::LONGITUDE_REF]) && $this->exif_data[self::LONGITUDE_REF] === 'W') { $this->longitude *= -1; } + $this->latitude = $this->geo2float($this->exif_data[self::LATITUDE]); if (isset($this->exif_data[self::LATITUDE_REF]) && $this->exif_data[self::LATITUDE_REF] === 'S') { $this->latitude *= -1; } } + // optional if (isset($this->exif_data[self::TIMESTAMP])) { $t = $this->exif_data[self::TIMESTAMP]; @@ -262,27 +247,25 @@ private function parse(): void { } /** - * @param string $timestamp * @return int */ private function string2time(string $timestamp): ?int { - $result = null; if (preg_match('#' . self::EXIF_TIME_REGEX . '#ui', $timestamp, $match)) { - $result - = strtotime("{$match['years']}-{$match['months']}-{$match['days']} {$match['hours']}:{$match['minutes']}:{$match['seconds']}")?:null; + return strtotime(sprintf('%s-%s-%s %s:%s:%s', $match['years'], $match['months'], $match['days'], $match['hours'], $match['minutes'], $match['seconds']))?:null; } - return $result; + + return null; } /** * @param $geo - * @return float|null */ - private function geo2float($geo): ?float { + private function geo2float($geo): float { if (!is_array($geo)) { $geo = [$geo]; } + $result = .0; $d = 1.0; foreach ($geo as $component) { @@ -293,28 +276,22 @@ private function geo2float($geo): ?float { return $result; } - /** - * @param string $value - * @return float|null - */ private function string2float(string $value): ?float { $result = null; $value = trim($value, '/'); if (str_contains($value, '/')) { - $value = array_map('intval', explode('/', $value)); + $value = array_map(intval(...), explode('/', $value)); if ($value[1] != 0) { $result = $value[0] / $value[1]; } } else { $result = floatval($value); } + return $result; } - /** - * @return bool - */ public function isZeroIsland(): bool { return $this->latitude() === .0 && $this->longitude() === .0; } @@ -333,20 +310,17 @@ public function longitude(int $precision = 6): ?float { return $this->longitude === null ? null : round($this->longitude, $precision); } - /** - * @param string|null $format - * @return string|int|null - */ - public function timestamp(?string $format = 'Y-m-d H:i:s') { - $result = $this->timestamp; + public function timestamp(?string $format = 'Y-m-d H:i:s'): int|string|null { if ($this->timestamp !== null && $format) { - $result = date($format, $this->timestamp); + return date($format, $this->timestamp); } - return $result; + + return $this->timestamp; } /** * If someone wants to have it as a json object + * @return array */ public function jsonSerialize(): array { return [ @@ -362,20 +336,15 @@ public function jsonSerialize(): array { * @param $name * @return float|int|string|null */ - public function __get($name) { + public function __get(string $name): mixed { $value = null; - switch ($name) { - case 'lat': - $value = $this->latitude(); - break; - case 'lng': - $value = $this->longitude(); - break; - case 'dateTaken': - $value = $this->timestamp(null); - break; - } - return $value; + + return match ($name) { + 'lat' => $this->latitude(), + 'lng' => $this->longitude(), + 'dateTaken' => $this->timestamp(null), + default => $value, + }; } } diff --git a/lib/Helper/functions.php b/lib/Helper/functions.php index cf04f75f4..bd936974c 100644 --- a/lib/Helper/functions.php +++ b/lib/Helper/functions.php @@ -1,5 +1,7 @@ * @@ -21,22 +23,19 @@ * along with this program. If not, see . * */ - namespace OCA\Maps\Helper; use RuntimeException; /** * function remove_utf8_bom - * - * @param string $text - * @return string */ function remove_utf8_bom(string $text): string { $bom = pack('H*', 'EFBBBF'); - $text = preg_replace("/^$bom/", '', $text); + $text = preg_replace(sprintf('/^%s/', $bom), '', $text); if ($text === null) { throw new RuntimeException(preg_last_error_msg()); } + return $text; } diff --git a/lib/Hooks/FileHooks.php b/lib/Hooks/FileHooks.php index 0be737a4c..b73c54511 100644 --- a/lib/Hooks/FileHooks.php +++ b/lib/Hooks/FileHooks.php @@ -1,5 +1,7 @@ * @copyright Piotr Bator 2017 */ - namespace OCA\Maps\Hooks; use OC\Files\Filesystem; @@ -19,7 +20,10 @@ use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\Node; +use OCP\IUserSession; use OCP\Lock\ILockingProvider; +use OCP\Server; +use OCP\Share; use OCP\Share\IShare; use OCP\Util; use function OCP\Log\logger; @@ -30,20 +34,19 @@ class FileHooks { public function __construct( - private IRootFolder $root, - private PhotofilesService $photofilesService, - private TracksService $tracksService, - private ILockingProvider $lockingProvider, + private readonly IRootFolder $root, + private readonly PhotofilesService $photofilesService, + private readonly TracksService $tracksService, + private readonly ILockingProvider $lockingProvider, ) { } public function register(): void { - $fileWriteCallback = function (\OCP\Files\Node $node) { + $fileWriteCallback = function (Node $node): void { //logger('maps')->debug("Hook postWrite"); if ($node instanceof File && $this->isUserNode($node) && $node->getSize()) { $path = $node->getPath(); - if (!$this->lockingProvider->isLocked($path, ILockingProvider::LOCK_SHARED) - and !$this->lockingProvider->isLocked($path, ILockingProvider::LOCK_EXCLUSIVE) + if (!$this->lockingProvider->isLocked($path, ILockingProvider::LOCK_SHARED) && !$this->lockingProvider->isLocked($path, ILockingProvider::LOCK_EXCLUSIVE) ) { $isPhoto = $this->photofilesService->addByFile($node); if (!$isPhoto) { @@ -54,7 +57,7 @@ public function register(): void { }; $this->root->listen('\OC\Files', 'postWrite', $fileWriteCallback); - $fileDeletionCallback = function (\OCP\Files\Node $node) { + $fileDeletionCallback = function (Node $node): void { //logger('maps')->debug("Hook preDelete"); if ($this->isUserNode($node)) { if ($node instanceof Folder) { @@ -70,15 +73,15 @@ public function register(): void { // this one is triggered when restoring a version of a file // and NOT when it's created so we can use it for updating coordinates in DB - $this->root->listen('\OC\Files', 'postTouch', function (\OCP\Files\Node $node) { - if ($this->isUserNode($node) and $node instanceof File) { + $this->root->listen('\OC\Files', 'postTouch', function (Node $node): void { + if ($this->isUserNode($node) && $node instanceof File) { $this->photofilesService->updateByFile($node); // nothing to update on tracks, metadata will be regenerated when getting content if etag has changed } }); // move file: delete then add it again in DB to be sure it's there for all users with access to target file - $this->root->listen('\OC\Files', 'postRename', function (\OCP\Files\Node $source, \OCP\Files\Node $target) { + $this->root->listen('\OC\Files', 'postRename', function (Node $source, Node $target): void { if ($this->isUserNode($target)) { if ($target instanceof File) { // if moved (parents are different) => update DB with access list @@ -102,11 +105,14 @@ public function register(): void { Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', $this, 'restore'); // sharing hooks - Util::connectHook(\OCP\Share::class, 'post_shared', $this, 'postShare'); - Util::connectHook(\OCP\Share::class, 'post_unshare', $this, 'postUnShare'); - Util::connectHook(\OCP\Share::class, 'pre_unshare', $this, 'preUnShare'); + Util::connectHook(Share::class, 'post_shared', $this, 'postShare'); + Util::connectHook(Share::class, 'post_unshare', $this, 'postUnShare'); + Util::connectHook(Share::class, 'pre_unshare', $this, 'preUnShare'); } + /** + * @param array $params + */ public function postShare(array $params): void { //logger('maps')->debug("Hook postShare"); if ($params['itemType'] === 'file') { @@ -117,6 +123,7 @@ public function postShare(array $params): void { if (!$file instanceof File) { return; } + $this->photofilesService->addByFile($file); $this->tracksService->safeAddByFile($file); } elseif ($params['itemType'] === 'folder') { @@ -125,36 +132,44 @@ public function postShare(array $params): void { if (!$folder instanceof Folder) { return; } + $this->photofilesService->addByFolder($folder); $this->tracksService->safeAddByFolder($folder); } } + /** + * @param array $params + */ public function postUnShare(array $params): void { //logger('maps')->debug("Hook postUnShare"); - if ($params['shareType'] === IShare::TYPE_USER) { - if ($params['itemType'] === 'file') { - $targetUserId = $params['shareWith']; - $fileId = $params['fileSource']; // or itemSource - $this->photofilesService->deleteByFileIdUserId($fileId, $targetUserId); - $this->tracksService->safeDeleteByFileIdUserId($fileId, $targetUserId); - } + if ($params['shareType'] === IShare::TYPE_USER && $params['itemType'] === 'file') { + $targetUserId = $params['shareWith']; + $fileId = $params['fileSource']; + // or itemSource + $this->photofilesService->deleteByFileIdUserId($fileId, $targetUserId); + $this->tracksService->safeDeleteByFileIdUserId($fileId, $targetUserId); } } + /** + * @param array $params + */ public function preUnShare(array $params): void { //logger('maps')->debug("Hook preUnShare"); - if ($params['shareType'] === IShare::TYPE_USER) { - if ($params['itemType'] === 'folder') { - $targetUserId = $params['shareWith']; - $dirId = $params['fileSource']; // or itemSource - $this->photofilesService->deleteByFolderIdUserId($dirId, $targetUserId); - $this->tracksService->safeDeleteByFolderIdUserId($dirId, $targetUserId); - } + if ($params['shareType'] === IShare::TYPE_USER && $params['itemType'] === 'folder') { + $targetUserId = $params['shareWith']; + $dirId = $params['fileSource']; + // or itemSource + $this->photofilesService->deleteByFolderIdUserId($dirId, $targetUserId); + $this->tracksService->safeDeleteByFolderIdUserId($dirId, $targetUserId); } } - public function restore($params): void { + /** + * @param array $params + */ + public function restore(array $params): void { $node = $this->getNodeForPath($params['filePath']); if ($this->isUserNode($node)) { if ($node instanceof Folder) { @@ -167,18 +182,19 @@ public function restore($params): void { } } - private function getNodeForPath($path): Node { - $user = \OC::$server->getUserSession()->getUser(); + private function getNodeForPath(string $path): Node { + $user = Server::get(IUserSession::class)->getUser(); $fullPath = Filesystem::normalizePath('/' . $user->getUID() . '/files/' . $path); return $this->root->get($fullPath); } - private function isUserNode(\OCP\Files\Node $node): bool { + private function isUserNode(Node $node): bool { //return $node->getStorage()->instanceOfStorage("\OCP\Files\IHomeStorage") $owner = $node->getStorage()->getOwner(''); if (! $owner) { return false; } + return str_starts_with($node->getPath(), '/' . $owner . '/'); } diff --git a/lib/Listener/CardCreatedListener.php b/lib/Listener/CardCreatedListener.php index 5c2e890b5..8e5a90570 100644 --- a/lib/Listener/CardCreatedListener.php +++ b/lib/Listener/CardCreatedListener.php @@ -31,13 +31,9 @@ /** @template-implements IEventListener */ class CardCreatedListener implements IEventListener { - /** @var AddressService */ - private $addressService; - public function __construct( - AddressService $addressService, + private readonly AddressService $addressService, ) { - $this->addressService = $addressService; } public function handle(Event $event): void { @@ -45,6 +41,7 @@ public function handle(Event $event): void { // Unrelated return; } + $cData = $event->getCardData(); $cUri = $cData['uri']; $this->addressService->scheduleVCardForLookup($cData['carddata'], $cUri); diff --git a/lib/Listener/CardDeletedListener.php b/lib/Listener/CardDeletedListener.php index 1eaefef10..27fc9ec52 100644 --- a/lib/Listener/CardDeletedListener.php +++ b/lib/Listener/CardDeletedListener.php @@ -31,13 +31,9 @@ /** @template-implements IEventListener */ class CardDeletedListener implements IEventListener { - /** @var AddressService */ - private $addressService; - public function __construct( - AddressService $addressService, + private readonly AddressService $addressService, ) { - $this->addressService = $addressService; } public function handle(Event $event): void { @@ -45,6 +41,7 @@ public function handle(Event $event): void { // Unrelated return; } + $cData = $event->getCardData(); $cUri = $cData['uri']; $this->addressService->deleteDBContactAddresses($cUri); diff --git a/lib/Listener/CardUpdatedListener.php b/lib/Listener/CardUpdatedListener.php index 6092b02f5..0f03447c4 100644 --- a/lib/Listener/CardUpdatedListener.php +++ b/lib/Listener/CardUpdatedListener.php @@ -31,13 +31,9 @@ /** @template-implements IEventListener */ class CardUpdatedListener implements IEventListener { - /** @var AddressService */ - private $addressService; - public function __construct( - AddressService $addressService, + private readonly AddressService $addressService, ) { - $this->addressService = $addressService; } public function handle(Event $event): void { @@ -45,6 +41,7 @@ public function handle(Event $event): void { // Unrelated return; } + $cData = $event->getCardData(); $cUri = $cData['uri']; $this->addressService->scheduleVCardForLookup($cData['carddata'], $cUri); diff --git a/lib/Listener/LoadAdditionalScriptsListener.php b/lib/Listener/LoadAdditionalScriptsListener.php index 83ad9a697..7d1dfc803 100644 --- a/lib/Listener/LoadAdditionalScriptsListener.php +++ b/lib/Listener/LoadAdditionalScriptsListener.php @@ -31,9 +31,6 @@ /** @template-implements IEventListener */ class LoadAdditionalScriptsListener implements IEventListener { - public function __construct() { - } - public function handle(Event $event): void { if (!($event instanceof LoadAdditionalScriptsEvent)) { // Unrelated diff --git a/lib/Listener/LoadSidebarListener.php b/lib/Listener/LoadSidebarListener.php index f0761769d..3527e2800 100644 --- a/lib/Listener/LoadSidebarListener.php +++ b/lib/Listener/LoadSidebarListener.php @@ -31,9 +31,6 @@ /** @template-implements IEventListener */ class LoadSidebarListener implements IEventListener { - public function __construct() { - } - public function handle(Event $event): void { if (!($event instanceof LoadSidebar)) { // Unrelated diff --git a/lib/Migration/InstallScan.php b/lib/Migration/InstallScan.php index cd6a3a41d..67019f456 100644 --- a/lib/Migration/InstallScan.php +++ b/lib/Migration/InstallScan.php @@ -1,5 +1,7 @@ * @@ -21,17 +23,18 @@ * along with this program. If not, see . * */ - namespace OCA\Maps\Migration; use OCA\Maps\BackgroundJob\LaunchUsersInstallScanJob; use OCP\BackgroundJob\IJobList; use OCP\Encryption\IManager; +use OCP\IAppConfig; use OCP\IConfig; use OCP\IUser; use OCP\IUserManager; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; +use Override; /** * Class InstallScan @@ -41,33 +44,22 @@ class InstallScan implements IRepairStep { public function __construct( - private IConfig $config, - private IUserManager $userManager, - private IJobList $jobList, - private IManager $encryptionManager, + private readonly IAppConfig $appConfig, + private readonly IConfig $config, + private readonly IUserManager $userManager, + private readonly IJobList $jobList, + private readonly IManager $encryptionManager, ) { - $this->config = $config; - $this->jobList = $jobList; - $this->encryptionManager = $encryptionManager; - $this->userManager = $userManager; } - /** - * Returns the step's name - * - * @return string - * @since 9.1.0 - */ - public function getName() { + #[Override] + public function getName(): string { return 'Scan photos and tracks in users storages'; } - /** - * @param IOutput $output - */ - public function run(IOutput $output) { + public function run(IOutput $output): ?int { if (!$this->shouldRun()) { - return; + return null; } if ($this->encryptionManager->isEnabled()) { @@ -77,15 +69,16 @@ public function run(IOutput $output) { // set the install scan flag for existing users // future users won't have any value and won't be bothered by "media scan" warning - $this->userManager->callForSeenUsers(function (IUser $user) { + $this->userManager->callForSeenUsers(function (IUser $user): void { $this->config->setUserValue($user->getUID(), 'maps', 'installScanDone', 'no'); }); // create the job which will create a job by user $this->jobList->add(LaunchUsersInstallScanJob::class, []); + return null; } - protected function shouldRun() { - $appVersion = $this->config->getAppValue('maps', 'installed_version', '0.0.0'); + protected function shouldRun(): bool { + $appVersion = $this->appConfig->getValueString('maps', 'installed_version', '0.0.0'); return version_compare($appVersion, '0.0.10', '<'); } diff --git a/lib/Migration/RegisterMimeType.php b/lib/Migration/RegisterMimeType.php index 2e6575195..4e2eee022 100644 --- a/lib/Migration/RegisterMimeType.php +++ b/lib/Migration/RegisterMimeType.php @@ -1,5 +1,7 @@ mimeTypeLoader = $mimeTypeLoader; } - public function getName() { + public function getName(): string { return 'Register Maps MIME types'; } - private function registerForExistingFiles() { + private function registerForExistingFiles(): void { $mimeTypeId = $this->mimeTypeLoader->getId('application/x-nextcloud-maps'); $this->mimeTypeLoader->updateFilecache('maps', $mimeTypeId); @@ -36,7 +38,7 @@ private function registerForExistingFiles() { $this->mimeTypeLoader->updateFilecache('notrack', $mimeTypeId); } - private function registerForNewFiles() { + private function registerForNewFiles(): void { $mapping = [ 'maps' => ['application/x-nextcloud-maps'], 'noindex' => ['application/x-nextcloud-noindex'], @@ -56,7 +58,7 @@ private function registerForNewFiles() { file_put_contents($mappingFile, json_encode($mapping, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); } - public function run(IOutput $output) { + public function run(IOutput $output): void { $output->info('Registering the mimetype...'); // Register the mime type for existing files diff --git a/lib/Migration/UnregisterMimeType.php b/lib/Migration/UnregisterMimeType.php index 3e5dd2085..edcec2ee8 100644 --- a/lib/Migration/UnregisterMimeType.php +++ b/lib/Migration/UnregisterMimeType.php @@ -1,5 +1,7 @@ mimeTypeLoader = $mimeTypeLoader; } - public function getName() { + public function getName(): string { return 'Unregister Maps MIME types'; } - private function unregisterForExistingFiles() { + private function unregisterForExistingFiles(): void { $mimeTypeId = $this->mimeTypeLoader->getId('application/octet-stream'); $this->mimeTypeLoader->updateFilecache('maps', $mimeTypeId); $this->mimeTypeLoader->updateFilecache('noindex', $mimeTypeId); @@ -28,7 +30,7 @@ private function unregisterForExistingFiles() { $this->mimeTypeLoader->updateFilecache('notrack', $mimeTypeId); } - private function unregisterForNewFiles() { + private function unregisterForNewFiles(): void { $mappingFile = \OC::$configDir . self::CUSTOM_MIMETYPEMAPPING; if (file_exists($mappingFile)) { @@ -42,11 +44,12 @@ private function unregisterForNewFiles() { } else { $mapping = []; } + file_put_contents($mappingFile, json_encode($mapping, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); } } - public function run(IOutput $output) { + public function run(IOutput $output): void { $output->info('Unregistering the mimetype...'); // Register the mime type for existing files diff --git a/lib/Migration/Version000008Date20190428142257.php b/lib/Migration/Version000008Date20190428142257.php index 69676057a..14441f7e9 100644 --- a/lib/Migration/Version000008Date20190428142257.php +++ b/lib/Migration/Version000008Date20190428142257.php @@ -15,17 +15,13 @@ class Version000008Date20190428142257 extends SimpleMigrationStep { /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options * @return null|ISchemaWrapper */ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { @@ -218,13 +214,12 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt ]); $table->setPrimaryKey(['id']); } + return $schema; } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } diff --git a/lib/Migration/Version000009Date20190625000800.php b/lib/Migration/Version000009Date20190625000800.php index a426e698f..c99b40c23 100644 --- a/lib/Migration/Version000009Date20190625000800.php +++ b/lib/Migration/Version000009Date20190625000800.php @@ -15,17 +15,13 @@ class Version000009Date20190625000800 extends SimpleMigrationStep { /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options * @return null|ISchemaWrapper */ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { @@ -68,9 +64,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } diff --git a/lib/Migration/Version000012Date20190703155323.php b/lib/Migration/Version000012Date20190703155323.php index 430d1899b..083356d8b 100644 --- a/lib/Migration/Version000012Date20190703155323.php +++ b/lib/Migration/Version000012Date20190703155323.php @@ -15,24 +15,19 @@ */ class Version000012Date20190703155323 extends SimpleMigrationStep { - protected $db; - - public function __construct(IDBConnection $connection) { - $this->db = $connection; + public function __construct( + protected IDBConnection $db, + ) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options * @return null|ISchemaWrapper */ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { @@ -46,9 +41,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } diff --git a/lib/Migration/Version000012Date20190722184716.php b/lib/Migration/Version000012Date20190722184716.php index 2f3e0af28..47649c1ed 100644 --- a/lib/Migration/Version000012Date20190722184716.php +++ b/lib/Migration/Version000012Date20190722184716.php @@ -15,24 +15,19 @@ */ class Version000012Date20190722184716 extends SimpleMigrationStep { - protected $db; - - public function __construct(IDBConnection $connection) { - $this->db = $connection; + public function __construct( + protected IDBConnection $db, + ) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options * @return null|ISchemaWrapper */ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { @@ -76,9 +71,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } diff --git a/lib/Migration/Version000013Date20190723185417.php b/lib/Migration/Version000013Date20190723185417.php index 19b89a085..9abe66d72 100644 --- a/lib/Migration/Version000013Date20190723185417.php +++ b/lib/Migration/Version000013Date20190723185417.php @@ -15,24 +15,19 @@ */ class Version000013Date20190723185417 extends SimpleMigrationStep { - protected $db; - - public function __construct(IDBConnection $connection) { - $this->db = $connection; + public function __construct( + protected IDBConnection $db, + ) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options * @return null|ISchemaWrapper */ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { @@ -43,6 +38,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt if ($table->hasColumn('contact_uid')) { $table->dropColumn('contact_uid'); } + $table->addColumn('object_uri', 'string', [ 'notnull' => true, 'default' => '--', @@ -55,11 +51,9 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ - public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { $query = $this->db->getQueryBuilder(); $query->delete('maps_address_geo'); $query->executeStatement(); diff --git a/lib/Migration/Version000014Date20190817184844.php b/lib/Migration/Version000014Date20190817184844.php index c84713d67..4ef8c559c 100644 --- a/lib/Migration/Version000014Date20190817184844.php +++ b/lib/Migration/Version000014Date20190817184844.php @@ -15,24 +15,19 @@ */ class Version000014Date20190817184844 extends SimpleMigrationStep { - protected $db; - - public function __construct(IDBConnection $connection) { - $this->db = $connection; + public function __construct( + protected IDBConnection $db, + ) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options * @return null|ISchemaWrapper */ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { @@ -50,9 +45,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } diff --git a/lib/Migration/Version000102Date20190901152326.php b/lib/Migration/Version000102Date20190901152326.php index 043abb257..b72f01c01 100644 --- a/lib/Migration/Version000102Date20190901152326.php +++ b/lib/Migration/Version000102Date20190901152326.php @@ -15,24 +15,19 @@ */ class Version000102Date20190901152326 extends SimpleMigrationStep { - protected $db; - - public function __construct(IDBConnection $connection) { - $this->db = $connection; + public function __construct( + protected IDBConnection $db, + ) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options * @return null|ISchemaWrapper */ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { @@ -51,9 +46,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } diff --git a/lib/Migration/Version000106Date20191118221134.php b/lib/Migration/Version000106Date20191118221134.php index 929531421..32efa7e9c 100644 --- a/lib/Migration/Version000106Date20191118221134.php +++ b/lib/Migration/Version000106Date20191118221134.php @@ -15,17 +15,13 @@ class Version000106Date20191118221134 extends SimpleMigrationStep { /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options * @return null|ISchemaWrapper */ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { @@ -59,9 +55,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } diff --git a/lib/Migration/Version000107Date20200608220000.php b/lib/Migration/Version000107Date20200608220000.php index 2e418f998..989f6be21 100644 --- a/lib/Migration/Version000107Date20200608220000.php +++ b/lib/Migration/Version000107Date20200608220000.php @@ -15,24 +15,19 @@ */ class Version000107Date20200608220000 extends SimpleMigrationStep { - protected $db; - - public function __construct(IDBConnection $connection) { - $this->db = $connection; + public function __construct( + protected IDBConnection $db, + ) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options * @return null|ISchemaWrapper */ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { @@ -50,9 +45,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } diff --git a/lib/Migration/Version000108Date20230310220000.php b/lib/Migration/Version000108Date20230310220000.php index c8f323548..3fad313f2 100644 --- a/lib/Migration/Version000108Date20230310220000.php +++ b/lib/Migration/Version000108Date20230310220000.php @@ -15,24 +15,19 @@ */ class Version000108Date20230310220000 extends SimpleMigrationStep { - protected $db; - - public function __construct(IDBConnection $connection) { - $this->db = $connection; + public function __construct( + protected IDBConnection $db, + ) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options * @return null|ISchemaWrapper */ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { @@ -43,13 +38,12 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $table->addIndex(['user_id']); $table->addIndex(['file_id']); } + return $schema; } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } diff --git a/lib/Migration/Version100100Date20230731135102.php b/lib/Migration/Version100100Date20230731135102.php index 85a15fd68..c1474e994 100644 --- a/lib/Migration/Version100100Date20230731135102.php +++ b/lib/Migration/Version100100Date20230731135102.php @@ -15,24 +15,19 @@ */ class Version100100Date20230731135102 extends SimpleMigrationStep { - protected $db; - - public function __construct(IDBConnection $connection) { - $this->db = $connection; + public function __construct( + protected IDBConnection $db, + ) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options * @return null|ISchemaWrapper */ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { @@ -42,6 +37,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt if ($schema->hasTable('maps_device_shares')) { $schema->dropTable('maps_device_shares'); } + if (!$schema->hasTable('maps_device_shares')) { $table = $schema->createTable('maps_device_shares'); $table->addColumn('id', 'bigint', [ @@ -73,9 +69,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt } /** - * @param IOutput $output * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options */ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) { } diff --git a/lib/Service/AddressService.php b/lib/Service/AddressService.php index c6480b208..ff3779321 100644 --- a/lib/Service/AddressService.php +++ b/lib/Service/AddressService.php @@ -1,5 +1,7 @@ dbconnection = $dbconnection; $this->memcache = $cacheFactory->createLocal('maps'); $this->jobList = $jobList; - $this->appData = $appData; } // converts the address to geo lat;lon @@ -73,9 +73,16 @@ public function addressToGeo($adr, $uri): string { * @param $adr * @param $uri ressource identifier (contact URI for example) * @return array($lat,$lng,$lookedUp) + * @return array + * @return array + * @return array + * @return array + * @return array + * @return array + * @return array */ public function lookupAddress($adr, $uri): array { - $adr_norm = strtolower(preg_replace('/\s+/', '', $adr)); + $adr_norm = strtolower((string)preg_replace('/\s+/', '', (string)$adr)); $qb = $this->dbconnection->getQueryBuilder(); $qb->select('id', 'lat', 'lng', 'looked_up') ->from('maps_address_geo') @@ -101,38 +108,39 @@ public function lookupAddress($adr, $uri): array { if (!$geo[2]) { $geo = $this->lookupAddressExternal($adr); } + $lat = $geo[0]; $lng = $geo[1]; $lookedUp = $geo[2]; $inDb = true; } + break; } + $req->closeCursor(); $qb = $this->dbconnection->getQueryBuilder(); // if it's still not in the DB, it means the lookup did not happen yet // so we can schedule it for later if (!$inDb) { - if (strlen($adr) > 255) { + if (strlen((string)$adr) > 255) { $this->logger->notice('lookupAddress: Truncating $adr (entry too long) ' . $adr); - $adr = substr($adr, 0, 255); + $adr = substr((string)$adr, 0, 255); } + $foo = $this->scheduleForLookup($adr, $uri); $id = $foo[0]; $lat = $foo[1]; $lng = $foo[2]; $lookedUp = $foo[3]; - - } else { - if ($lookedUp) { - $qb->update('maps_address_geo') - ->set('lat', $qb->createNamedParameter($lat, IQueryBuilder::PARAM_STR)) - ->set('lng', $qb->createNamedParameter($lng, IQueryBuilder::PARAM_STR)) - ->set('object_uri', $qb->createNamedParameter($uri, IQueryBuilder::PARAM_STR)) - ->set('looked_up', $qb->createNamedParameter($lookedUp, IQueryBuilder::PARAM_BOOL)) - ->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_STR))); - $qb->executeStatement(); - } + } elseif ($lookedUp) { + $qb->update('maps_address_geo') + ->set('lat', $qb->createNamedParameter($lat, IQueryBuilder::PARAM_STR)) + ->set('lng', $qb->createNamedParameter($lng, IQueryBuilder::PARAM_STR)) + ->set('object_uri', $qb->createNamedParameter($uri, IQueryBuilder::PARAM_STR)) + ->set('looked_up', $qb->createNamedParameter($lookedUp, IQueryBuilder::PARAM_BOOL)) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_STR))); + $qb->executeStatement(); } return [$lat, $lng, $lookedUp]; @@ -149,7 +157,7 @@ private function lookupAddressInternal($adr): array { return $res; } - $adr_norm = strtolower(preg_replace('/\s+/', '', $adr)); + $adr_norm = strtolower((string)preg_replace('/\s+/', '', (string)$adr)); $qb = $this->dbconnection->getQueryBuilder(); $qb->select('lat', 'lng') @@ -162,6 +170,7 @@ private function lookupAddressInternal($adr): array { $res[1] = $row['lng']; $res[2] = true; } + $req->closeCursor(); return $res; @@ -169,7 +178,7 @@ private function lookupAddressInternal($adr): array { // looks up the address on external provider returns lat, lon, lookupstate // do lookup only if last one occured more than one second ago - private function lookupAddressExternal($adr): array { + private function lookupAddressExternal(string $adr): array { if (time() - intval($this->memcache->get('lastAddressLookup')) >= 1) { $opts = [ 'http' => [ @@ -182,9 +191,9 @@ private function lookupAddressExternal($adr): array { // we get rid of "post office box" field $splitted_adr = explode(';', $adr); // remove blank lines (#706) - $splitted_adr = array_filter(array_map('trim', $splitted_adr)); + $splitted_adr = array_filter(array_map(trim(...), $splitted_adr)); // ADR in VCard is mandated to 7 fields - if (sizeof($splitted_adr) == 7) { + if (count($splitted_adr) === 7) { $query_adr_parts = []; // This matches the nominatim query with the fields of 'ADR' in VCard $query_key_part = ['','','street', 'city','state', 'postalcode', 'country']; @@ -208,30 +217,36 @@ private function lookupAddressExternal($adr): array { ); if ($result_json !== false) { $result = \json_decode($result_json, true); - if (!(key_exists('request_failed', $result) and $result['request_failed'])) { + if (!(array_key_exists('request_failed', $result) && $result['request_failed'])) { $this->logger->debug('External looked up address: ' . $adr . ' with result' . print_r($result, true)); $this->memcache->set('lastAddressLookup', time()); $lat = null; $lon = null; foreach ($result as $addr) { - if (key_exists('lat', $addr) and key_exists('lon', $addr)) { - if (is_null($lat) - or (key_exists('category', $addr) and in_array($addr['category'], ['place', 'building', 'amenity']))) { - $lat = $addr['lat']; - $lon = $addr['lon']; - } + if (!(array_key_exists('lat', $addr) && array_key_exists('lon', $addr))) { + continue; + } + + if (!is_null($lat) && !(array_key_exists('category', $addr) && in_array($addr['category'], ['place', 'building', 'amenity']))) { + continue; } + + $lat = $addr['lat']; + $lon = $addr['lon']; } + return [$lat, $lon, true]; } } + $this->logger->debug('Externally looked failed'); } + return [null, null, false]; } // launch lookup for all addresses of the vCard - public function scheduleVCardForLookup($cardData, $cardUri) { + public function scheduleVCardForLookup($cardData, $cardUri): void { $vCard = Reader::read($cardData); $this->cleanUpDBContactAddresses($vCard, $cardUri); @@ -246,16 +261,17 @@ public function scheduleVCardForLookup($cardData, $cardUri) { } } - private function cleanUpDBContactAddresses($vCard, $uri) { + private function cleanUpDBContactAddresses($vCard, $uri): void { $qb = $this->dbconnection->getQueryBuilder(); // get all vcard addresses $vCardAddresses = []; foreach ($vCard->children() as $property) { if ($property->name === 'ADR') { $adr = $property->getValue(); - array_push($vCardAddresses, $adr); + $vCardAddresses[] = $adr; } } + // check which addresses from DB is not in the vCard anymore $adrIdToDelete = []; $qb->select('id', 'adr') @@ -264,9 +280,10 @@ private function cleanUpDBContactAddresses($vCard, $uri) { $req = $qb->executeQuery(); while ($row = $req->fetch()) { if (!in_array($row['adr'], $vCardAddresses)) { - array_push($adrIdToDelete, $row['id']); + $adrIdToDelete[] = $row['id']; } } + $req->closeCursor(); foreach ($adrIdToDelete as $id) { @@ -279,7 +296,7 @@ private function cleanUpDBContactAddresses($vCard, $uri) { } } - public function deleteDBContactAddresses($uri) { + public function deleteDBContactAddresses($uri): void { $qb = $this->dbconnection->getQueryBuilder(); $qb->delete('maps_address_geo') ->where( @@ -289,13 +306,17 @@ public function deleteDBContactAddresses($uri) { } // schedules the address for an external lookup + /** + * @return array + */ private function scheduleForLookup($adr, $uri): array { $geo = $this->lookupAddressInternal($adr); // if not found internally, ask external service if (!$geo[2]) { $geo = $this->lookupAddressExternal($adr); } - $adr_norm = strtolower(preg_replace('/\s+/', '', $adr)); + + $adr_norm = strtolower((string)preg_replace('/\s+/', '', (string)$adr)); $qb = $this->dbconnection->getQueryBuilder(); $qb->insert('maps_address_geo') ->values([ @@ -311,6 +332,7 @@ private function scheduleForLookup($adr, $uri): array { if (!$geo[2]) { $this->jobList->add(LookupMissingGeoJob::class, []); } + return [$id, $geo[0], $geo[1], $geo[2]]; } @@ -329,24 +351,28 @@ public function lookupMissingGeo($max = 200):bool { $req->closeCursor(); $i = 0; foreach ($result as $row) { - $i++; + ++$i; $geo = $this->lookupAddress($row['adr'], $row['object_uri']); // lookup failed if (!$geo[2]) { $lookedUpAll = false; } + \sleep(1); - \usleep(\rand(100, 100000)); + \usleep(random_int(100, 100000)); } + // not all addresses where loaded from database if ($i === $max) { $lookedUpAll = false; } + if ($lookedUpAll) { $this->logger->debug('Successfully looked up all addresses during cron job'); } else { $this->logger->debug('Failed to look up all addresses during cron job'); } + return $lookedUpAll; } } diff --git a/lib/Service/DevicesService.php b/lib/Service/DevicesService.php index 4f562d666..2e7d33e83 100644 --- a/lib/Service/DevicesService.php +++ b/lib/Service/DevicesService.php @@ -1,5 +1,7 @@ dbconnection->quote($str); - } - /** - * @param string $userId - * @param int $pruneBefore * @return array with devices */ - public function getDevicesFromDB($userId) { + public function getDevicesFromDB(string $userId): array { $devices = []; $qb = $this->dbconnection->getQueryBuilder(); $qb->select('id', 'user_agent', 'color') @@ -72,16 +73,16 @@ public function getDevicesFromDB($userId) { 'shares' => [] ]; } + $req->closeCursor(); return $devices; } /** * @param string[] $tokens - * @return array * @throws Exception */ - public function getDevicesByTokens(array $tokens) { + public function getDevicesByTokens(array $tokens): array { $devices = []; $qb = $this->dbconnection->getquerybuilder(); $qb->select('d.id', 'd.user_agent', 'd.color', 's.token') @@ -109,15 +110,15 @@ public function getDevicesByTokens(array $tokens) { ]; } } + $req->closeCursor(); return $devices; } /** - * @return array * @throws \OCP\DB\Exception */ - public function getDevicePointsFromDB(string $userId, int $deviceId, ?int $pruneBefore = 0, ?int $limit = null, ?int $offset = null) { + public function getDevicePointsFromDB(string $userId, int $deviceId, ?int $pruneBefore = 0, ?int $limit = null, ?int $offset = null): array { $qb = $this->dbconnection->getQueryBuilder(); // get coordinates $qb->selectDistinct(['p.id', 'lat', 'lng', 'timestamp', 'altitude', 'accuracy', 'battery']) @@ -134,12 +135,15 @@ public function getDevicePointsFromDB(string $userId, int $deviceId, ?int $prune $qb->expr()->gt('timestamp', $qb->createNamedParameter(intval($pruneBefore), IQueryBuilder::PARAM_INT)) ); } + if (!is_null($offset)) { $qb->setFirstResult($offset); } + if (!is_null($limit)) { $qb->setMaxResults($limit); } + $qb->orderBy('timestamp', 'DESC'); $req = $qb->executeQuery(); @@ -155,6 +159,7 @@ public function getDevicePointsFromDB(string $userId, int $deviceId, ?int $prune 'battery' => is_numeric($row['battery']) ? floatval($row['battery']) : null ]; } + $req->closeCursor(); return array_reverse($points); @@ -162,13 +167,9 @@ public function getDevicePointsFromDB(string $userId, int $deviceId, ?int $prune /** * @param string[] $token - * @param int|null $pruneBefore - * @param int|null $limit - * @param int|null $offset - * @return array * @throws Exception */ - public function getDevicePointsByTokens(array $tokens, ?int $pruneBefore = 0, ?int $limit = 10000, ?int $offset = 0) { + public function getDevicePointsByTokens(array $tokens, ?int $pruneBefore = 0, ?int $limit = 10000, ?int $offset = 0): array { $qb = $this->dbconnection->getQueryBuilder(); // get coordinates $or = []; @@ -179,6 +180,7 @@ public function getDevicePointsByTokens(array $tokens, ?int $pruneBefore = 0, ?i $qb->expr()->gte('p.timestamp', 's.timestamp_from') ); } + $qb->select('p.id', 'lat', 'lng', 'timestamp', 'altitude', 'accuracy', 'battery') ->from('maps_device_points', 'p') ->innerJoin('p', 'maps_device_shares', 's', $qb->expr()->eq('p.device_id', 's.device_id')) @@ -189,12 +191,15 @@ public function getDevicePointsByTokens(array $tokens, ?int $pruneBefore = 0, ?i $qb->expr()->gt('timestamp', $qb->createNamedParameter(intval($pruneBefore), IQueryBuilder::PARAM_INT)) ); } + if (!is_null($offset)) { $qb->setFirstResult($offset); } + if (!is_null($limit)) { $qb->setMaxResults($limit); } + $qb->orderBy('timestamp', 'DESC'); $req = $qb->executeQuery(); @@ -210,6 +215,7 @@ public function getDevicePointsByTokens(array $tokens, ?int $pruneBefore = 0, ?i 'battery' => is_numeric($row['battery']) ? floatval($row['battery']) : null ]; } + $req->closeCursor(); return array_reverse($points); @@ -218,10 +224,9 @@ public function getDevicePointsByTokens(array $tokens, ?int $pruneBefore = 0, ?i /** * @param $userId * @param $deviceId - * @return array * @throws Exception */ - public function getDeviceTimePointsFromDb($userId, $deviceId) { + public function getDeviceTimePointsFromDb(string $userId, int $deviceId): array { $qb = $this->dbconnection->getQueryBuilder(); // get coordinates $qb->select('lat', 'lng', 'timestamp') @@ -240,11 +245,12 @@ public function getDeviceTimePointsFromDb($userId, $deviceId) { while ($row = $req->fetch()) { $points[intval($row['timestamp'])] = [floatval($row['lat']), floatval($row['lng'])]; } + $req->closeCursor(); return $points; } - public function getOrCreateDeviceFromDB($userId, $userAgent) { + public function getOrCreateDeviceFromDB(string $userId, string $userAgent) { $deviceId = null; $qb = $this->dbconnection->getQueryBuilder(); $qb->select('id') @@ -261,6 +267,7 @@ public function getOrCreateDeviceFromDB($userId, $userAgent) { $deviceId = intval($row['id']); break; } + $req->closeCursor(); if ($deviceId === null) { @@ -272,6 +279,7 @@ public function getOrCreateDeviceFromDB($userId, $userAgent) { $qb->executeStatement(); $deviceId = $qb->getLastInsertId(); } + return $deviceId; } @@ -288,23 +296,23 @@ public function addPointToDB($deviceId, $lat, $lng, $ts, $altitude, $battery, $a 'accuracy' => $qb->createNamedParameter(is_numeric($accuracy) ? $accuracy : null, IQueryBuilder::PARAM_STR) ]); $qb->executeStatement(); - $pointId = $qb->getLastInsertId(); - return $pointId; + return $qb->getLastInsertId(); } - public function addPointsToDB(int $deviceId, array $points): void { + public function addPointsToDB($deviceId, array $points): void { try { $this->dbconnection->beginTransaction(); foreach ($points as $p) { $this->addPointToDB($deviceId, $p['lat'], $p['lng'], $p['date'], $p['altitude'] ?? null, $p['battery'] ?? null, $p['accuracy'] ?? null); } + $this->dbconnection->commit(); - } catch (Exception $ex) { + } catch (Exception) { $this->dbconnection->rollBack(); } } - public function getDeviceFromDB($id, $userId) { + public function getDeviceFromDB(int $id, ?string $userId): ?array { $device = null; $qb = $this->dbconnection->getQueryBuilder(); $qb->select('id', 'user_agent', 'color') @@ -317,6 +325,7 @@ public function getDeviceFromDB($id, $userId) { $qb->expr()->eq('user_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)) ); } + $req = $qb->executeQuery(); while ($row = $req->fetch()) { @@ -327,26 +336,29 @@ public function getDeviceFromDB($id, $userId) { ]; break; } + $req->closeCursor(); return $device; } - public function editDeviceInDB($id, $color, $name) { + public function editDeviceInDB(int $id, ?string $color, ?string $name): void { $qb = $this->dbconnection->getQueryBuilder(); $qb->update('maps_devices'); - if (is_string($color) && strlen($color) > 0) { + if (is_string($color) && $color !== '') { $qb->set('color', $qb->createNamedParameter($color, IQueryBuilder::PARAM_STR)); } - if (is_string($name) && strlen($name) > 0) { + + if (is_string($name) && $name !== '') { $qb->set('user_agent', $qb->createNamedParameter($name, IQueryBuilder::PARAM_STR)); } + $qb->where( $qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)) ); $qb->executeStatement(); } - public function deleteDeviceFromDB($id) { + public function deleteDeviceFromDB(int $id): void { $qb = $this->dbconnection->getQueryBuilder(); $qb->delete('maps_devices') ->where( @@ -361,7 +373,7 @@ public function deleteDeviceFromDB($id) { $qb->executeStatement(); } - public function countPoints($userId, $deviceIdList, $begin, $end) { + public function countPoints(string $userId, array $deviceIdList, ?int $begin, ?int $end): int { $qb = $this->dbconnection->getQueryBuilder(); $qb->select($qb->createFunction('COUNT(*) AS co')) ->from('maps_devices', 'd') @@ -369,25 +381,29 @@ public function countPoints($userId, $deviceIdList, $begin, $end) { ->where( $qb->expr()->eq('d.user_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)) ); - if (is_array($deviceIdList) and count($deviceIdList) > 0) { + if ($deviceIdList !== []) { $or = $qb->expr()->orx(); foreach ($deviceIdList as $deviceId) { $or->add($qb->expr()->eq('d.id', $qb->createNamedParameter($deviceId, IQueryBuilder::PARAM_INT))); } + $qb->andWhere($or); } else { return 0; } - if ($begin !== null && is_numeric($begin)) { + + if ($begin !== null) { $qb->andWhere( $qb->expr()->gt('p.timestamp', $qb->createNamedParameter(intval($begin), IQueryBuilder::PARAM_INT)) ); } - if ($end !== null && is_numeric($end)) { + + if ($end !== null) { $qb->andWhere( $qb->expr()->lt('p.timestamp', $qb->createNamedParameter(intval($end), IQueryBuilder::PARAM_INT)) ); } + $req = $qb->executeQuery(); $count = 0; while ($row = $req->fetch()) { @@ -398,7 +414,7 @@ public function countPoints($userId, $deviceIdList, $begin, $end) { return $count; } - public function exportDevices($userId, $handler, $deviceIdList, $begin, $end, $appVersion, $filename) { + public function exportDevices(string $userId, $handler, $deviceIdList, $begin, $end, string $appVersion, string $filename): void { $gpxHeader = $this->generateGpxHeader($filename, $appVersion, count($deviceIdList)); fwrite($handler, $gpxHeader); @@ -408,10 +424,11 @@ public function exportDevices($userId, $handler, $deviceIdList, $begin, $end, $a $this->getAndWriteDevicePoints($devid, $begin, $end, $handler, $nbPoints, $userId); } } + fwrite($handler, ''); } - private function generateGpxHeader($name, $appVersion, $nbdev = 0) { + private function generateGpxHeader(string $name, string $appVersion, int $nbdev = 0): string { date_default_timezone_set('UTC'); $dt = new \DateTime(); $date = $dt->format('Y-m-d\TH:i:s\Z'); @@ -436,11 +453,11 @@ private function generateGpxHeader($name, $appVersion, $nbdev = 0) { if ($nbdev > 0) { $gpxText .= ' ' . $nbdev . ' device' . ($nbdev > 1 ? 's' : '') . '' . "\n"; } - $gpxText .= '' . "\n"; - return $gpxText; + + return $gpxText . ('' . "\n"); } - private function getAndWriteDevicePoints($devid, $begin, $end, $fd, $nbPoints, $userId) { + private function getAndWriteDevicePoints(int $devid, $begin, $end, $fd, int $nbPoints, string $userId): void { $device = $this->getDeviceFromDB($devid, $userId); $devname = $device['user_agent']; $qb = $this->dbconnection->getQueryBuilder(); @@ -464,11 +481,13 @@ private function getAndWriteDevicePoints($devid, $begin, $end, $fd, $nbPoints, $ $qb->expr()->gt('timestamp', $qb->createNamedParameter(intval($begin), IQueryBuilder::PARAM_INT)) ); } + if (intval($end) > 0) { $qb->andWhere( $qb->expr()->lt('timestamp', $qb->createNamedParameter(intval($end), IQueryBuilder::PARAM_INT)) ); } + $qb->setFirstResult($pointIndex); $qb->setMaxResults($chunkSize); $qb->orderBy('timestamp', 'ASC'); @@ -482,9 +501,10 @@ private function getAndWriteDevicePoints($devid, $begin, $end, $fd, $nbPoints, $ $date = ''; if (is_numeric($epoch)) { $epoch = intval($epoch); - $dt = new \DateTime("@$epoch"); + $dt = new \DateTime('@' . $epoch); $date = $dt->format('Y-m-d\TH:i:s\Z'); } + $alt = $row['altitude']; $acc = $row['accuracy']; $bat = $row['battery']; @@ -495,43 +515,53 @@ private function getAndWriteDevicePoints($devid, $begin, $end, $fd, $nbPoints, $ if (is_numeric($alt)) { $gpxText .= ' ' . sprintf('%.2f', floatval($alt)) . '' . "\n"; } + if (is_numeric($acc) && intval($acc) >= 0) { $gpxExtension .= ' ' . sprintf('%.2f', floatval($acc)) . '' . "\n"; } + if (is_numeric($bat) && intval($bat) >= 0) { $gpxExtension .= ' ' . sprintf('%.2f', floatval($bat)) . '' . "\n"; } + if ($gpxExtension !== '') { $gpxText .= ' ' . "\n" . $gpxExtension; $gpxText .= ' ' . "\n"; } + $gpxText .= ' ' . "\n"; } + $req->closeCursor(); // write the chunk fwrite($fd, $gpxText); - $pointIndex = $pointIndex + $chunkSize; + $pointIndex += $chunkSize; } + $gpxText = ' ' . "\n"; $gpxText .= '' . "\n"; fwrite($fd, $gpxText); } - public function importDevices($userId, $file) { + public function importDevices(string $userId, File $file) { $lowerFileName = strtolower($file->getName()); if ($this->endswith($lowerFileName, '.gpx')) { return $this->importDevicesFromGpx($userId, $file); - } elseif ($this->endswith($lowerFileName, '.kml')) { + } + + if ($this->endswith($lowerFileName, '.kml')) { $fp = $file->fopen('r'); $name = $file->getName(); return $this->importDevicesFromKml($userId, $fp, $name); - } elseif ($this->endswith($lowerFileName, '.kmz')) { + } + + if ($this->endswith($lowerFileName, '.kmz')) { return $this->importDevicesFromKmz($userId, $file); } } - public function importDevicesFromGpx($userId, $file) { + public function importDevicesFromGpx(string $userId, File $file): int { $this->currentPointList = []; $this->importUserId = $userId; $this->importFileName = $file->getName(); @@ -540,14 +570,14 @@ public function importDevicesFromGpx($userId, $file) { $xml_parser = xml_parser_create(); xml_set_object($xml_parser, $this); - xml_set_element_handler($xml_parser, 'gpxStartElement', 'gpxEndElement'); - xml_set_character_data_handler($xml_parser, 'gpxDataElement'); + xml_set_element_handler($xml_parser, $this->gpxStartElement(...), $this->gpxEndElement(...)); + xml_set_character_data_handler($xml_parser, $this->gpxDataElement(...)); $fp = $file->fopen('r'); // using xml_parse to be able to parse file chunks in case it's too big while ($data = fread($fp, 4096000)) { - if (!xml_parse($xml_parser, $data, feof($fp))) { + if (xml_parse($xml_parser, $data, feof($fp)) === 0) { $this->logger->error( 'Exception in ' . $file->getName() . ' parsing at line ' . xml_get_current_line_number($xml_parser) . ' : ' @@ -557,13 +587,17 @@ public function importDevicesFromGpx($userId, $file) { return 0; } } + fclose($fp); xml_parser_free($xml_parser); return ($this->trackIndex - 1); } - private function gpxStartElement($parser, $name, $attrs) { + /** + * @param array $attrs + */ + private function gpxStartElement($parser, $name, array $attrs): void { //$points, array($lat, $lon, $ele, $timestamp, $acc, $bat, $sat, $ua, $speed, $bearing) $this->currentXmlTag = $name; if ($name === 'TRK') { @@ -576,14 +610,16 @@ private function gpxStartElement($parser, $name, $attrs) { if (isset($attrs['LAT'])) { $this->currentPoint['lat'] = floatval($attrs['LAT']); } + if (isset($attrs['LON'])) { $this->currentPoint['lng'] = floatval($attrs['LON']); } } + //var_dump($attrs); } - private function gpxEndElement($parser, $name) { + private function gpxEndElement($parser, $name): void { if ($name === 'TRK') { $this->insideTrk = false; // log last track points @@ -591,10 +627,12 @@ private function gpxEndElement($parser, $name) { if ($this->importDevName === '') { $this->importDevName = $this->importFileName . ' ' . $this->trackIndex; } + $devid = $this->getOrCreateDeviceFromDB($this->importUserId, $this->importDevName); $this->addPointsToDB($devid, $this->currentPointList); } - $this->trackIndex++; + + ++$this->trackIndex; unset($this->currentPointList); } elseif ($name === 'TRKPT') { // store track point @@ -605,64 +643,65 @@ private function gpxEndElement($parser, $name) { $timestamp = $time->getTimestamp(); $this->currentPoint['date'] = $timestamp; } - array_push($this->currentPointList, $this->currentPoint); + + $this->currentPointList[] = $this->currentPoint; // if we have enough points, we log them and clean the points array if (count($this->currentPointList) >= 500) { if ($this->importDevName === '') { $this->importDevName = 'device' . $this->trackIndex; } + $devid = $this->getOrCreateDeviceFromDB($this->importUserId, $this->importDevName); $this->addPointsToDB($devid, $this->currentPointList); unset($this->currentPointList); $this->currentPointList = []; } - $this->pointIndex++; + + ++$this->pointIndex; } } - private function gpxDataElement($parser, $data) { - $d = trim($data); - if (!empty($d)) { + private function gpxDataElement($parser, $data): void { + $d = trim((string)$data); + if ($d !== '' && $d !== '0') { if ($this->currentXmlTag === 'ELE') { $this->currentPoint['altitude'] = (isset($this->currentPoint['altitude'])) ? $this->currentPoint['altitude'] . $d : $d; } elseif ($this->currentXmlTag === 'BATTERYLEVEL') { $this->currentPoint['battery'] = (isset($this->currentPoint['battery'])) ? $this->currentPoint['battery'] . $d : $d; } elseif ($this->currentXmlTag === 'ACCURACY') { $this->currentPoint['accuracy'] = (isset($this->currentPoint['accuracy'])) ? $this->currentPoint['accuracy'] . $d : $d; - } elseif ($this->insideTrk and $this->currentXmlTag === 'TIME') { + } elseif ($this->insideTrk && $this->currentXmlTag === 'TIME') { $this->currentPoint['date'] = (isset($this->currentPoint['date'])) ? $this->currentPoint['date'] . $d : $d; - } elseif ($this->insideTrk and $this->currentXmlTag === 'NAME') { - $this->importDevName = $this->importDevName . $d; + } elseif ($this->insideTrk && $this->currentXmlTag === 'NAME') { + $this->importDevName .= $d; } } } - public function importDevicesFromKmz($userId, $file) { + public function importDevicesFromKmz(string $userId, File $file): int { $path = $file->getStorage()->getLocalFile($file->getInternalPath()); $name = $file->getName(); $zf = new ZIP($path); - if (count($zf->getFiles()) > 0) { + if ($zf->getFiles() !== []) { $zippedFilePath = $zf->getFiles()[0]; $fstream = $zf->getStream($zippedFilePath, 'r'); - - $nbImported = $this->importDevicesFromKml($userId, $fstream, $name); - } else { - $nbImported = 0; + return $this->importDevicesFromKml($userId, $fstream, $name); } - return $nbImported; + + return 0; } - public function importDevicesFromKml($userId, $fp, $name) { + public function importDevicesFromKml(string $userId, $fp, string $name): int { $this->trackIndex = 1; $this->importUserId = $userId; $this->importFileName = $name; $xml_parser = xml_parser_create(); xml_set_object($xml_parser, $this); - xml_set_element_handler($xml_parser, 'kmlStartElement', 'kmlEndElement'); - xml_set_character_data_handler($xml_parser, 'kmlDataElement'); + xml_set_element_handler($xml_parser, $this->kmlStartElement(...), $this->kmlEndElement(...)); + xml_set_character_data_handler($xml_parser, $this->kmlDataElement(...)); while ($data = fread($fp, 4096000)) { - if (!xml_parse($xml_parser, $data, feof($fp))) { + if (xml_parse($xml_parser, $data, feof($fp)) === 0) { $this->logger->error( 'Exception in ' . $name . ' parsing at line ' . xml_get_current_line_number($xml_parser) . ' : ' @@ -671,35 +710,38 @@ public function importDevicesFromKml($userId, $fp, $name) { return 0; } } + fclose($fp); xml_parser_free($xml_parser); return ($this->trackIndex - 1); } - private function kmlStartElement($parser, $name, $attrs) { + /** + * @param array $attrs + */ + private function kmlStartElement($parser, $name, array $attrs): void { $this->currentXmlTag = $name; if ($name === 'GX:TRACK') { - if (isset($attrs['ID'])) { - $this->importDevName = $attrs['ID']; - } else { - $this->importDevName = $this->importFileName . ' ' . $this->trackIndex; - } + $this->importDevName = $attrs['ID'] ?? $this->importFileName . ' ' . $this->trackIndex; + $this->pointIndex = 1; $this->currentPointList = []; } elseif ($name === 'WHEN') { $this->currentPoint = []; } + //var_dump($attrs); } - private function kmlEndElement($parser, $name) { + private function kmlEndElement($parser, $name): void { if ($name === 'GX:TRACK') { // log last track points if (count($this->currentPointList) > 0) { $devid = $this->getOrCreateDeviceFromDB($this->importUserId, $this->importDevName); $this->addPointsToDB($devid, $this->currentPointList); } - $this->trackIndex++; + + ++$this->trackIndex; unset($this->currentPointList); } elseif ($name === 'GX:COORD') { // convert date @@ -708,6 +750,7 @@ private function kmlEndElement($parser, $name) { $timestamp = $time->getTimestamp(); $this->currentPoint['date'] = $timestamp; } + // get latlng if (isset($this->currentPoint['coords'])) { $spl = explode(' ', $this->currentPoint['coords']); @@ -719,8 +762,9 @@ private function kmlEndElement($parser, $name) { } } } + // store track point - array_push($this->currentPointList, $this->currentPoint); + $this->currentPointList[] = $this->currentPoint; // if we have enough points, we log them and clean the points array if (count($this->currentPointList) >= 500) { $devid = $this->getOrCreateDeviceFromDB($this->importUserId, $this->importDevName); @@ -728,13 +772,14 @@ private function kmlEndElement($parser, $name) { unset($this->currentPointList); $this->currentPointList = []; } - $this->pointIndex++; + + ++$this->pointIndex; } } - private function kmlDataElement($parser, $data) { - $d = trim($data); - if (!empty($d)) { + private function kmlDataElement($parser, $data): void { + $d = trim((string)$data); + if ($d !== '' && $d !== '0') { if ($this->currentXmlTag === 'WHEN') { $this->currentPoint['date'] = (isset($this->currentPoint['date'])) ? $this->currentPoint['date'] . $d : $d; } elseif ($this->currentXmlTag === 'GX:COORD') { @@ -743,31 +788,32 @@ private function kmlDataElement($parser, $data) { } } - private function endswith($string, $test) { - $strlen = strlen($string); + private function endswith($string, string $test) { + $strlen = strlen((string)$string); $testlen = strlen($test); if ($testlen > $strlen) { return false; } - return substr_compare($string, $test, $strlen - $testlen, $testlen) === 0; + + return substr_compare((string)$string, $test, $strlen - $testlen, $testlen) === 0; } /** - * @return mixed * @throws NotFoundException */ - public function getSharedDevicesFromFolder(Folder $folder, bool $isCreatable = true) { + public function getSharedDevicesFromFolder(Folder $folder, bool $isCreatable = true): mixed { try { /** @var File $file */ $file = $folder->get('.device_shares.json'); - } catch (NotFoundException $e) { + } catch (NotFoundException) { if ($isCreatable) { $file = $folder->newFile('.device_shares.json', $content = '[]'); } else { throw new NotFoundException(); } } - return json_decode($file->getContent(), true); + + return json_decode((string)$file->getContent(), true); } } diff --git a/lib/Service/FavoritesService.php b/lib/Service/FavoritesService.php index 8e3fb1af7..23a85c9d1 100644 --- a/lib/Service/FavoritesService.php +++ b/lib/Service/FavoritesService.php @@ -1,5 +1,7 @@ expr()->gt('date_modified', $qb->createNamedParameter($pruneBefore, IQueryBuilder::PARAM_INT)) ); } + if ($filterCategory !== null) { $qb->andWhere( $qb->expr()->eq('category', $qb->createNamedParameter($filterCategory, IQueryBuilder::PARAM_STR)) ); } + $req = $qb->executeQuery(); while ($row = $req->fetch()) { @@ -90,6 +101,7 @@ public function getFavoritesFromDB(string $userId, int $pruneBefore = 0, ?string 'isShareable' => $isShareable, ]; } + $req->closeCursor(); return $favorites; } @@ -107,11 +119,13 @@ public function getFavoriteFromDB(int $id, ?string $userId = null, ?string $cate $qb->expr()->eq('user_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)) ); } + if ($category !== null) { $qb->andWhere( $qb->expr()->eq('category', $qb->createNamedParameter($category, IQueryBuilder::PARAM_STR)) ); } + $req = $qb->executeQuery(); while ($row = $req->fetch()) { @@ -141,6 +155,7 @@ public function getFavoriteFromDB(int $id, ?string $userId = null, ?string $cate ]; break; } + $req->closeCursor(); return $favorite; } @@ -173,33 +188,43 @@ public function addMultipleFavoritesToDB(string $userId, array $favoriteList): v try { $this->dbconnection->beginTransaction(); foreach ($favoriteList as $fav) { - if ( - !isset($fav['lat']) or !is_numeric($fav['lat']) - or !isset($fav['lng']) or !is_numeric($fav['lng']) - ) { + if (!isset($fav['lat'])) { + continue; + } + if (!is_numeric($fav['lat'])) { + continue; + } + if (!isset($fav['lng'])) { + continue; + } + if (!is_numeric($fav['lng'])) { continue; - } else { - $lat = floatval($fav['lat']); - $lng = floatval($fav['lng']); } + $lat = floatval($fav['lat']); + $lng = floatval($fav['lng']); + $values = [ 'user_id' => $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR), 'date_modified' => $qb->createNamedParameter($nowTimeStamp, IQueryBuilder::PARAM_INT), 'lat' => $qb->createNamedParameter($lat, IQueryBuilder::PARAM_INT), 'lng' => $qb->createNamedParameter($lng, IQueryBuilder::PARAM_INT), ]; - if (isset($fav['name']) and $fav['name'] !== '') { + if (isset($fav['name']) && $fav['name'] !== '') { $values['name'] = $qb->createNamedParameter($fav['name'], IQueryBuilder::PARAM_STR); } + if (isset($fav['date_created']) && is_numeric($fav['date_created'])) { $values['date_created'] = $qb->createNamedParameter($fav['date_created'], IQueryBuilder::PARAM_STR); } + if (isset($fav['category']) && $fav['category'] !== '') { $values['category'] = $qb->createNamedParameter($fav['category'], IQueryBuilder::PARAM_STR); } + if (isset($fav['comment']) && $fav['comment'] !== '') { $values['comment'] = $qb->createNamedParameter($fav['comment'], IQueryBuilder::PARAM_STR); } + if (isset($fav['extensions']) && $fav['extensions'] !== '') { $values['extensions'] = $qb->createNamedParameter($fav['extensions'], IQueryBuilder::PARAM_STR); } @@ -207,6 +232,7 @@ public function addMultipleFavoritesToDB(string $userId, array $favoriteList): v $qb->values($values); $qb->executeStatement(); } + $this->dbconnection->commit(); } catch (\Throwable) { $this->dbconnection->rollback(); @@ -226,7 +252,7 @@ public function renameCategoryInDB(string $userId, $cat, $newName): void { $qb->executeStatement(); } - public function editFavoriteInDB($id, $name, $lat, $lng, $category, $comment, $extensions) { + public function editFavoriteInDB($id, $name, $lat, $lng, $category, $comment, $extensions): void { $nowTimeStamp = (new \DateTime())->getTimestamp(); $qb = $this->dbconnection->getQueryBuilder(); $qb->update('maps_favorites'); @@ -234,21 +260,27 @@ public function editFavoriteInDB($id, $name, $lat, $lng, $category, $comment, $e if ($name !== null) { $qb->set('name', $qb->createNamedParameter($name, IQueryBuilder::PARAM_STR)); } + if ($lat !== null) { $qb->set('lat', $qb->createNamedParameter($lat, IQueryBuilder::PARAM_STR)); } + if ($lng !== null) { $qb->set('lng', $qb->createNamedParameter($lng, IQueryBuilder::PARAM_STR)); } + if ($category !== null) { $qb->set('category', $qb->createNamedParameter($category, IQueryBuilder::PARAM_STR)); } + if ($comment !== null) { $qb->set('comment', $qb->createNamedParameter($comment, IQueryBuilder::PARAM_STR)); } + if ($extensions !== null) { $qb->set('extensions', $qb->createNamedParameter($extensions, IQueryBuilder::PARAM_STR)); } + $qb->where( $qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)) ); @@ -264,7 +296,7 @@ public function deleteFavoriteFromDB(int $id): void { $qb->executeStatement(); } - public function deleteFavoritesFromDB($ids, $userId) { + public function deleteFavoritesFromDB($ids, $userId): void { $qb = $this->dbconnection->getQueryBuilder(); $qb->delete('maps_favorites') ->where( @@ -275,19 +307,21 @@ public function deleteFavoritesFromDB($ids, $userId) { foreach ($ids as $id) { $or->add($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT))); } + $qb->andWhere($or); } else { return; } + $qb->executeStatement(); } - public function countFavorites($userId, $categoryList, $begin, $end) { - if ($categoryList === null - or (is_array($categoryList) and count($categoryList) === 0) + public function countFavorites($userId, $categoryList, $begin, $end): int { + if ($categoryList === null || is_array($categoryList) && count($categoryList) === 0 ) { return 0; } + $qb = $this->dbconnection->getQueryBuilder(); $qb->select($qb->createFunction('COUNT(*) AS co')) ->from('maps_favorites', 'f') @@ -299,35 +333,37 @@ public function countFavorites($userId, $categoryList, $begin, $end) { $qb->expr()->gt('date_created', $qb->createNamedParameter($begin, IQueryBuilder::PARAM_INT)) ); } + if ($end !== null) { $qb->andWhere( $qb->expr()->lt('date_created', $qb->createNamedParameter($end, IQueryBuilder::PARAM_INT)) ); } + // apply category restrictions if it's a non-empty array - if (!is_string($categoryList) - and is_array($categoryList) - and count($categoryList) > 0 + if (!is_string($categoryList) && is_array($categoryList) && count($categoryList) > 0 ) { $or = $qb->expr()->orx(); foreach ($categoryList as $cat) { $or->add($qb->expr()->eq('category', $qb->createNamedParameter($cat, IQueryBuilder::PARAM_STR))); } + $qb->andWhere($or); } + $nbFavorites = 0; $req = $qb->executeQuery(); while ($row = $req->fetch()) { $nbFavorites = intval($row['co']); break; } + $req->closeCursor(); return $nbFavorites; } /** - * @return array * @throws \Exception */ public function getFavoritesFromJSON(File $file): array { @@ -361,6 +397,7 @@ public function getFavoritesFromJSON(File $file): array { } else { $time = $value['properties']['Published']; } + $currentFavorite['date_created'] = $time; } elseif ($key === 'Updated') { if (!is_numeric($value['properties']['Updated'])) { @@ -369,6 +406,7 @@ public function getFavoritesFromJSON(File $file): array { } else { $time = $value['properties']['Updated']; } + $currentFavorite['date_modified'] = $time; } elseif ($key === 'Category') { $currentFavorite['category'] = $v; @@ -381,12 +419,15 @@ public function getFavoritesFromJSON(File $file): array { } + if (!array_key_exists('category', $currentFavorite)) { $currentFavorite['category'] = $this->l10n->t('Personal'); } + if (!array_key_exists('comment', $currentFavorite)) { $currentFavorite['comment'] = ''; } + if ( array_key_exists('Location', $value['properties']) && array_key_exists('Address', $value['properties']['Location']) @@ -396,7 +437,7 @@ public function getFavoritesFromJSON(File $file): array { // Store this favorite $favorites[] = $currentFavorite; - $id++; + ++$id; } return $favorites; @@ -406,12 +447,15 @@ public function getFavoriteFromJSON(File $file, int $id) { $favorites = $this->getFavoritesFromJSON($file); if (array_key_exists($id, $favorites)) { return $favorites[$id]; - } else { - return null; } + return null; } - private function addFavoriteToJSONData($data, $name, $lat, $lng, $category, $comment, $extensions, $nowTimeStamp) { + /** + * @param array $data + * @return array> + */ + private function addFavoriteToJSONData(array $data, $name, $lat, $lng, $category, $comment, $extensions, $nowTimeStamp): array { $favorite = [ 'type' => 'Feature', 'geometry' => [ @@ -434,6 +478,7 @@ private function addFavoriteToJSONData($data, $name, $lat, $lng, $category, $com $favorite['properties'][$key] = $value; } } + $id = array_push($data['features'], $favorite) - 1; return [ 'id' => $id, @@ -443,7 +488,7 @@ private function addFavoriteToJSONData($data, $name, $lat, $lng, $category, $com public function addFavoriteToJSON($file, $name, $lat, $lng, $category, $comment, $extensions) { $nowTimeStamp = (new \DateTime())->getTimestamp(); - $data = json_decode($file->getContent(), true, 512); + $data = json_decode((string)$file->getContent(), true, 512); $tmp = $this->addFavoriteToJSONData($data, $name, $lat, $lng, $category, $comment, $extensions, $nowTimeStamp); @@ -451,39 +496,45 @@ public function addFavoriteToJSON($file, $name, $lat, $lng, $category, $comment, return $tmp['id']; } - public function addFavoritesToJSON($file, $favorites) { + /** + * @return mixed[] + */ + public function addFavoritesToJSON($file, $favorites): array { $nowTimeStamp = (new \DateTime())->getTimestamp(); - $data = json_decode($file->getContent(), true, 512); + $data = json_decode((string)$file->getContent(), true, 512); $ids = []; foreach ($favorites as $favorite) { $tmp = $this->addFavoriteToJSONData($data, $favorite['name'], $favorite['lat'], $favorite['lng'], $favorite['category'], $favorite['comment'], $favorite['extensions'], $nowTimeStamp); $ids[] = $tmp['id']; $data = $tmp['data']; } + $file->putContent(json_encode($data, JSON_PRETTY_PRINT)); return $ids; } - public function renameCategoryInJSON($file, $cat, $newName) { + public function renameCategoryInJSON($file, $cat, $newName): void { $nowTimeStamp = (new \DateTime())->getTimestamp(); - $data = json_decode($file->getContent(), true, 512); + $data = json_decode((string)$file->getContent(), true, 512); $this->logger->debug($cat); foreach ($data['features'] as $key => $value) { if (!array_key_exists('Category', $value['properties'])) { $value['properties']['Category'] = $this->l10n->t('Personal'); $data['features'][$key]['properties']['Category'] = $this->l10n->t('Personal'); } + if (array_key_exists('Category', $value['properties']) && $value['properties']['Category'] == $cat) { $data['features'][$key]['properties']['Category'] = $newName; $data['features'][$key]['properties']['Updated'] = $nowTimeStamp; } } + $file->putContent(json_encode($data, JSON_PRETTY_PRINT)); } - public function editFavoriteInJSON($file, $id, $name, $lat, $lng, $category, $comment, $extensions) { + public function editFavoriteInJSON($file, $id, $name, $lat, $lng, $category, $comment, $extensions): void { $nowTimeStamp = (new \DateTime())->getTimestamp(); - $data = json_decode($file->getContent(), true, 512); + $data = json_decode((string)$file->getContent(), true, 512); $createdTimeStamp = $data['features'][$id]['properties']['Published']; $favorite = [ 'type' => 'Feature', @@ -514,22 +565,23 @@ public function editFavoriteInJSON($file, $id, $name, $lat, $lng, $category, $co } public function deleteFavoriteFromJSON($file, $id): int { - $data = json_decode($file->getContent(), true, 512); + $data = json_decode((string)$file->getContent(), true, 512); $countBefore = count($data['features']); array_splice($data['features'], $id, 1); $file->putContent(json_encode($data, JSON_PRETTY_PRINT)); return $countBefore - count($data['features']); } - public function deleteFavoritesFromJSON($file, $ids) { - $data = json_decode($file->getContent(), true, 512); + public function deleteFavoritesFromJSON($file, $ids): void { + $data = json_decode((string)$file->getContent(), true, 512); foreach ($ids as $id) { array_splice($data['features'], $id, 1); } + $file->putContent(json_encode($data, JSON_PRETTY_PRINT)); } - public function exportFavorites($userId, $fileHandler, $categoryList, $begin, $end, $appVersion) { + public function exportFavorites($userId, $fileHandler, $categoryList, $begin, $end, string $appVersion): void { $qb = $this->dbconnection->getQueryBuilder(); $nbFavorites = $this->countFavorites($userId, $categoryList, $begin, $end); @@ -556,22 +608,24 @@ public function exportFavorites($userId, $fileHandler, $categoryList, $begin, $e $qb->expr()->gte('date_created', $qb->createNamedParameter($begin, IQueryBuilder::PARAM_INT)) ); } + if ($end !== null) { $qb->andWhere( $qb->expr()->lte('date_created', $qb->createNamedParameter($end, IQueryBuilder::PARAM_INT)) ); } + // apply category restrictions if it's a non-empty array - if (!is_string($categoryList) - and is_array($categoryList) - and count($categoryList) > 0 + if (!is_string($categoryList) && is_array($categoryList) && count($categoryList) > 0 ) { $or = $qb->expr()->orx(); foreach ($categoryList as $cat) { $or->add($qb->expr()->eq('category', $qb->createNamedParameter($cat, IQueryBuilder::PARAM_STR))); } + $qb->andWhere($or); } + $qb->orderBy('date_created', 'ASC') ->setMaxResults($chunkSize) ->setFirstResult($favIndex); @@ -583,79 +637,92 @@ public function exportFavorites($userId, $fileHandler, $categoryList, $begin, $e $date = ''; if (is_numeric($epoch)) { $epoch = intval($epoch); - $dt = new \DateTime("@$epoch"); + $dt = new \DateTime('@' . $epoch); $date = $dt->format('Y-m-d\TH:i:s\Z'); } + $lat = $row['lat']; $lng = $row['lng']; - $category = str_replace('&', '&', $row['category']); - $comment = str_replace('&', '&', $row['comment']); - $extensions = str_replace('&', '&', $row['extensions']); + $category = str_replace('&', '&', (string)$row['category']); + $comment = str_replace('&', '&', (string)$row['comment']); + $extensions = str_replace('&', '&', (string)$row['extensions']); $gpxExtension = ''; $gpxText .= ' ' . "\n"; $gpxText .= ' ' . $name . '' . "\n"; $gpxText .= ' ' . "\n"; - if ($category !== null && strlen($category) > 0) { + if ($category !== null && (string)$category !== '') { $gpxText .= ' ' . $category . '' . "\n"; } else { $gpxText .= ' ' . $this->l10n->t('Personal') . '' . "\n"; } - if ($comment !== null && strlen($comment) > 0) { + + if ($comment !== null && (string)$comment !== '') { $gpxText .= ' ' . $comment . '' . "\n"; } - if ($extensions !== null && strlen($extensions) > 0) { + + if ($extensions !== null && (string)$extensions !== '') { $gpxExtension .= ' ' . $extensions . '' . "\n"; } + if ($gpxExtension !== '') { $gpxText .= ' ' . "\n" . $gpxExtension; $gpxText .= ' ' . "\n"; } + $gpxText .= ' ' . "\n"; } + $req->closeCursor(); // write the chunk ! fwrite($fileHandler, $gpxText); - $favIndex = $favIndex + $chunkSize; + $favIndex += $chunkSize; } + $gpxEnd = '' . "\n"; fwrite($fileHandler, $gpxEnd); } - public function importFavorites($userId, $file) { + public function importFavorites(string $userId, File $file): array { $lowerFileName = strtolower($file->getName()); if ($this->endswith($lowerFileName, '.gpx')) { return $this->importFavoritesFromGpx($userId, $file); - } elseif ($this->endswith($lowerFileName, '.kml')) { + } + if ($this->endswith($lowerFileName, '.kml')) { $fp = $file->fopen('r'); $name = $file->getName(); return $this->importFavoritesFromKml($userId, $fp, $name); - } elseif ($this->endswith($lowerFileName, '.kmz')) { + } + if ($this->endswith($lowerFileName, '.kmz')) { return $this->importFavoritesFromKmz($userId, $file); - } elseif ($this->endswith($lowerFileName, '.json') or $this->endswith($lowerFileName, '.geojson')) { + } + if ($this->endswith($lowerFileName, '.json') || $this->endswith($lowerFileName, '.geojson')) { return $this->importFavoritesFromGeoJSON($userId, $file); } + return [ + 'nbImported' => 0, + 'linesFound' => false + ]; } - public function importFavoritesFromKmz($userId, $file) { + public function importFavoritesFromKmz(string $userId, File $file): array { $path = $file->getStorage()->getLocalFile($file->getInternalPath()); $name = $file->getName(); $zf = new ZIP($path); - if (count($zf->getFiles()) > 0) { + if ($zf->getFiles() !== []) { $zippedFilePath = $zf->getFiles()[0]; $fstream = $zf->getStream($zippedFilePath, 'r'); - $result = $this->importFavoritesFromKml($userId, $fstream, $name); - } else { - $result = [ - 'nbImported' => 0, - 'linesFound' => false - ]; + return $this->importFavoritesFromKml($userId, $fstream, $name); } - return $result; + + return [ + 'nbImported' => 0, + 'linesFound' => false + ]; } - public function importFavoritesFromKml($userId, $fp, $name) { + public function importFavoritesFromKml(string $userId, $fp, string $name): array { $this->nbImported = 0; $this->linesFound = false; $this->currentFavoritesList = []; @@ -665,21 +732,25 @@ public function importFavoritesFromKml($userId, $fp, $name) { $xml_parser = xml_parser_create(); xml_set_object($xml_parser, $this); - xml_set_element_handler($xml_parser, 'kmlStartElement', 'kmlEndElement'); - xml_set_character_data_handler($xml_parser, 'kmlDataElement'); + xml_set_element_handler($xml_parser, $this->kmlStartElement(...), $this->kmlEndElement(...)); + xml_set_character_data_handler($xml_parser, $this->kmlDataElement(...)); // using xml_parse to be able to parse file chunks in case it's too big while ($data = fread($fp, 4096000)) { - if (!xml_parse($xml_parser, $data, feof($fp))) { + if (xml_parse($xml_parser, $data, feof($fp)) === 0) { $this->logger->error( 'Exception in ' . $name . ' parsing at line ' . xml_get_current_line_number($xml_parser) . ' : ' . xml_error_string(xml_get_error_code($xml_parser)), ['app' => 'maps'] ); - return 0; + return [ + 'nbImported' => 0, + 'linesFound' => 0, + ]; } } + fclose($fp); xml_parser_free($xml_parser); @@ -689,38 +760,42 @@ public function importFavoritesFromKml($userId, $fp, $name) { ]; } - private function kmlStartElement($parser, $name, $attrs) { + private function kmlStartElement($parser, $name, $attrs): void { $this->currentXmlTag = $name; if ($name === 'PLACEMARK') { $this->currentFavorite = []; $this->kmlInsidePlacemark = true; } + if ($name === 'LINESTRING') { $this->linesFound = true; } } - private function kmlEndElement($parser, $name) { + private function kmlEndElement($parser, $name): void { if ($name === 'KML') { // create last bunch if (count($this->currentFavoritesList) > 0) { $this->addMultipleFavoritesToDB($this->importUserId, $this->currentFavoritesList); } + unset($this->currentFavoritesList); } elseif ($name === 'PLACEMARK') { $this->kmlInsidePlacemark = false; // store favorite - $this->nbImported++; + ++$this->nbImported; $this->currentFavorite['category'] = $this->kmlCurrentCategory; - if (!isset($this->currentFavorite['category']) or $this->currentFavorite['category'] === '') { + if (!isset($this->currentFavorite['category']) || $this->currentFavorite['category'] === '') { $this->currentFavorite['category'] = $this->l10n->t('Personal'); } + // convert date if (isset($this->currentFavorite['date_created'])) { $time = new \DateTime($this->currentFavorite['date_created']); $timestamp = $time->getTimestamp(); $this->currentFavorite['date_created'] = $timestamp; } + if (isset($this->currentFavorite['coordinates'])) { $spl = explode(',', $this->currentFavorite['coordinates']); if (count($spl) > 1) { @@ -728,7 +803,8 @@ private function kmlEndElement($parser, $name) { $this->currentFavorite['lng'] = floatval($spl[0]); } } - array_push($this->currentFavoritesList, $this->currentFavorite); + + $this->currentFavoritesList[] = $this->currentFavorite; // if we have enough favorites, we create them and clean the array if (count($this->currentFavoritesList) >= 500) { $this->addMultipleFavoritesToDB($this->importUserId, $this->currentFavoritesList); @@ -738,28 +814,26 @@ private function kmlEndElement($parser, $name) { } } - private function kmlDataElement($parser, $data) { - $d = trim($data); - if (!empty($d)) { + private function kmlDataElement($parser, $data): void { + $d = trim((string)$data); + if ($d !== '' && $d !== '0') { if (!$this->kmlInsidePlacemark) { if ($this->currentXmlTag === 'NAME') { - $this->kmlCurrentCategory = $this->kmlCurrentCategory . $d; - } - } else { - if ($this->currentXmlTag === 'NAME') { - $this->currentFavorite['name'] = (isset($this->currentFavorite['name'])) ? $this->currentFavorite['name'] . $d : $d; - } elseif ($this->currentXmlTag === 'WHEN') { - $this->currentFavorite['date_created'] = (isset($this->currentFavorite['date_created'])) ? $this->currentFavorite['date_created'] . $d : $d; - } elseif ($this->currentXmlTag === 'COORDINATES') { - $this->currentFavorite['coordinates'] = (isset($this->currentFavorite['coordinates'])) ? $this->currentFavorite['coordinates'] . $d : $d; - } elseif ($this->currentXmlTag === 'DESCRIPTION') { - $this->currentFavorite['comment'] = (isset($this->currentFavorite['comment'])) ? $this->currentFavorite['comment'] . $d : $d; + $this->kmlCurrentCategory .= $d; } + } elseif ($this->currentXmlTag === 'NAME') { + $this->currentFavorite['name'] = (isset($this->currentFavorite['name'])) ? $this->currentFavorite['name'] . $d : $d; + } elseif ($this->currentXmlTag === 'WHEN') { + $this->currentFavorite['date_created'] = (isset($this->currentFavorite['date_created'])) ? $this->currentFavorite['date_created'] . $d : $d; + } elseif ($this->currentXmlTag === 'COORDINATES') { + $this->currentFavorite['coordinates'] = (isset($this->currentFavorite['coordinates'])) ? $this->currentFavorite['coordinates'] . $d : $d; + } elseif ($this->currentXmlTag === 'DESCRIPTION') { + $this->currentFavorite['comment'] = (isset($this->currentFavorite['comment'])) ? $this->currentFavorite['comment'] . $d : $d; } } } - public function importFavoritesFromGpx($userId, $file) { + public function importFavoritesFromGpx(string $userId, File $file): array { $this->nbImported = 0; $this->linesFound = false; $this->currentFavoritesList = []; @@ -768,23 +842,27 @@ public function importFavoritesFromGpx($userId, $file) { $xml_parser = xml_parser_create(); xml_set_object($xml_parser, $this); - xml_set_element_handler($xml_parser, 'gpxStartElement', 'gpxEndElement'); - xml_set_character_data_handler($xml_parser, 'gpxDataElement'); + xml_set_element_handler($xml_parser, $this->gpxStartElement(...), $this->gpxEndElement(...)); + xml_set_character_data_handler($xml_parser, $this->gpxDataElement(...)); $fp = $file->fopen('r'); // using xml_parse to be able to parse file chunks in case it's too big while ($data = fread($fp, 4096000)) { - if (!xml_parse($xml_parser, $data, feof($fp))) { + if (xml_parse($xml_parser, $data, feof($fp)) === 0) { $this->logger->error( 'Exception in ' . $file->getName() . ' parsing at line ' . xml_get_current_line_number($xml_parser) . ' : ' . xml_error_string(xml_get_error_code($xml_parser)), ['app' => 'maps'] ); - return 0; + return [ + 'nbImported' => 0, + 'linesFound' => false + ]; } } + fclose($fp); xml_parser_free($xml_parser); @@ -794,7 +872,10 @@ public function importFavoritesFromGpx($userId, $file) { ]; } - private function gpxStartElement($parser, $name, $attrs) { + /** + * @param array $attrs + */ + private function gpxStartElement($parser, $name, array $attrs): void { $this->currentXmlTag = $name; if ($name === 'WPT') { $this->insideWpt = true; @@ -802,36 +883,41 @@ private function gpxStartElement($parser, $name, $attrs) { if (isset($attrs['LAT'])) { $this->currentFavorite['lat'] = floatval($attrs['LAT']); } + if (isset($attrs['LON'])) { $this->currentFavorite['lng'] = floatval($attrs['LON']); } } - if ($name === 'TRK' or $name === 'RTE') { + + if ($name === 'TRK' || $name === 'RTE') { $this->linesFound = true; } } - private function gpxEndElement($parser, $name) { + private function gpxEndElement($parser, $name): void { if ($name === 'GPX') { // create last bunch if (count($this->currentFavoritesList) > 0) { $this->addMultipleFavoritesToDB($this->importUserId, $this->currentFavoritesList); } + unset($this->currentFavoritesList); } elseif ($name === 'WPT') { $this->insideWpt = false; // store favorite - $this->nbImported++; + ++$this->nbImported; // convert date if (isset($this->currentFavorite['date_created'])) { $time = new \DateTime($this->currentFavorite['date_created']); $timestamp = $time->getTimestamp(); $this->currentFavorite['date_created'] = $timestamp; } - if (!isset($this->currentFavorite['category']) or $this->currentFavorite['category'] === '') { + + if (!isset($this->currentFavorite['category']) || $this->currentFavorite['category'] === '') { $this->currentFavorite['category'] = $this->l10n->t('Personal'); } - array_push($this->currentFavoritesList, $this->currentFavorite); + + $this->currentFavoritesList[] = $this->currentFavorite; // if we have enough favorites, we create them and clean the array if (count($this->currentFavoritesList) >= 500) { $this->addMultipleFavoritesToDB($this->importUserId, $this->currentFavoritesList); @@ -841,24 +927,27 @@ private function gpxEndElement($parser, $name) { } } - private function gpxDataElement($parser, $data) { - $d = trim($data); - if (!empty($d)) { - if ($this->insideWpt and $this->currentXmlTag === 'NAME') { + private function gpxDataElement($parser, $data): void { + $d = trim((string)$data); + if ($d !== '' && $d !== '0') { + if ($this->insideWpt && $this->currentXmlTag === 'NAME') { $this->currentFavorite['name'] = (isset($this->currentFavorite['name'])) ? $this->currentFavorite['name'] . $d : $d; - } elseif ($this->insideWpt and $this->currentXmlTag === 'TIME') { + } elseif ($this->insideWpt && $this->currentXmlTag === 'TIME') { $this->currentFavorite['date_created'] = (isset($this->currentFavorite['date_created'])) ? $this->currentFavorite['date_created'] . $d : $d; - } elseif ($this->insideWpt and $this->currentXmlTag === 'TYPE') { + } elseif ($this->insideWpt && $this->currentXmlTag === 'TYPE') { $this->currentFavorite['category'] = (isset($this->currentFavorite['category'])) ? $this->currentFavorite['category'] . $d : $d; - } elseif ($this->insideWpt and $this->currentXmlTag === 'DESC') { + } elseif ($this->insideWpt && $this->currentXmlTag === 'DESC') { $this->currentFavorite['comment'] = (isset($this->currentFavorite['comment'])) ? $this->currentFavorite['comment'] . $d : $d; - } elseif ($this->insideWpt and $this->currentXmlTag === 'MAPS-EXTENSIONS') { + } elseif ($this->insideWpt && $this->currentXmlTag === 'MAPS-EXTENSIONS') { $this->currentFavorite['extensions'] = (isset($this->currentFavorite['extensions'])) ? $this->currentFavorite['extensions'] . $d : $d; } } } - public function importFavoritesFromGeoJSON($userId, $file) { + /** + * @return array + */ + public function importFavoritesFromGeoJSON($userId, $file): array { $this->nbImported = 0; $this->linesFound = false; $this->currentFavoritesList = []; @@ -866,9 +955,9 @@ public function importFavoritesFromGeoJSON($userId, $file) { // Decode file content from JSON - $data = json_decode($file->getContent(), true, 512); + $data = json_decode((string)$file->getContent(), true, 512); - if ($data == null or !isset($data['features'])) { + if ($data == null || !isset($data['features'])) { $this->logger->error( 'Exception parsing ' . $file->getName() . ': no places found to import', ['app' => 'maps'] @@ -876,7 +965,7 @@ public function importFavoritesFromGeoJSON($userId, $file) { } // Loop over all favorite entries - foreach ($data['features'] as $key => $value) { + foreach ($data['features'] as $value) { $this->currentFavorite = []; // Ensure that we have a valid GeoJSON Point geometry @@ -904,8 +993,8 @@ public function importFavoritesFromGeoJSON($userId, $file) { // Store this favorite - array_push($this->currentFavoritesList, $this->currentFavorite); - $this->nbImported++; + $this->currentFavoritesList[] = $this->currentFavorite; + ++$this->nbImported; // if we have enough favorites, we create them and clean the array if (count($this->currentFavoritesList) >= 500) { @@ -916,9 +1005,10 @@ public function importFavoritesFromGeoJSON($userId, $file) { } // Store last set of favorites - if (count($this->currentFavoritesList) > 0) { + if ($this->currentFavoritesList !== []) { $this->addMultipleFavoritesToDB($this->importUserId, $this->currentFavoritesList); } + unset($this->currentFavoritesList); return [ @@ -927,13 +1017,14 @@ public function importFavoritesFromGeoJSON($userId, $file) { ]; } - private function endswith($string, $test) { - $strlen = strlen($string); + private function endswith($string, string $test) { + $strlen = strlen((string)$string); $testlen = strlen($test); if ($testlen > $strlen) { return false; } - return substr_compare($string, $test, $strlen - $testlen, $testlen) === 0; + + return substr_compare((string)$string, $test, $strlen - $testlen, $testlen) === 0; } } diff --git a/lib/Service/GeophotoService.php b/lib/Service/GeophotoService.php index ac80a2524..2aa597821 100644 --- a/lib/Service/GeophotoService.php +++ b/lib/Service/GeophotoService.php @@ -1,5 +1,7 @@ * @copyright Piotr Bator 2017 */ - namespace OCA\Maps\Service; use OC\Files\Search\SearchBinaryOperator; @@ -31,18 +32,21 @@ use RuntimeException; class GeophotoService { - private ICache $photosCache; - private ICache $timeOrderedPointSetsCache; - private ICache $backgroundJobCache; - private $timeorderedPointSets = null; + private readonly ICache $photosCache; + + private readonly ICache $timeOrderedPointSetsCache; + + private readonly ICache $backgroundJobCache; + + private $timeorderedPointSets; public function __construct( - private IRootFolder $root, - private GeophotoMapper $photoMapper, - private IPreview $preview, - private TracksService $tracksService, - private DevicesService $devicesService, - private ICacheFactory $cacheFactory, + private readonly IRootFolder $root, + private readonly GeophotoMapper $photoMapper, + private readonly IPreview $preview, + private readonly TracksService $tracksService, + private readonly DevicesService $devicesService, + private readonly ICacheFactory $cacheFactory, ) { $this->photosCache = $this->cacheFactory->createDistributed('maps:photos'); $this->timeOrderedPointSetsCache = $this->cacheFactory->createDistributed('maps:time-ordered-point-sets'); @@ -73,13 +77,15 @@ public function getAll(string $userId, ?Folder $folder = null, bool $respectNome if (is_null($folder)) { $folder = $userFolder; } - $key = $userId . ':' . $userFolder->getRelativePath($folder->getPath()) . ':' . (string)$respectNomediaAndNoimage . ':' . (string)$hideImagesOnCustomMaps . ':' . (string)$hideImagesInMapsFolder; + + $key = $userId . ':' . $userFolder->getRelativePath($folder->getPath()) . ':' . $respectNomediaAndNoimage . ':' . $hideImagesOnCustomMaps . ':' . $hideImagesInMapsFolder; $filesById = $this->photosCache->get($key); if ($filesById === null) { $ignoredPaths = $respectNomediaAndNoimage ? $this->getIgnoredPaths($userId, $folder, $hideImagesOnCustomMaps) : []; if ($hideImagesInMapsFolder) { $ignoredPaths[] = '/Maps'; } + $photoEntities = $this->photoMapper->findAll($userId); $filesById = []; @@ -92,14 +98,16 @@ public function getAll(string $userId, ?Folder $folder = null, bool $respectNome if ($file === null) { continue; } + $path = $userFolder->getRelativePath($file->getPath()); $isIgnored = false; foreach ($ignoredPaths as $ignoredPath) { - if (str_starts_with($path, $ignoredPath)) { + if (str_starts_with($path, (string)$ignoredPath)) { $isIgnored = true; break; } } + if (!$isIgnored) { $isRoot = $file === $userFolder; @@ -127,15 +135,15 @@ public function getAll(string $userId, ?Folder $folder = null, bool $respectNome $filesById[] = $file_object; } } + $this->photosCache->set($key, $filesById, 60 * 60 * 24); } + return $filesById; } /** * @param string|null $timezone locale time zone used by images - * @param int $limit - * @param int $offset * @return array with geodatas of all nonLocalizedPhotos * @throws Exception * @throws NoUserException @@ -152,16 +160,14 @@ public function getNonLocalized(string $userId, ?Folder $folder = null, bool $re if ($hideImagesInMapsFolder) { $ignoredPaths[] = '/Maps'; } + $this->loadTimeorderedPointSets($userId, $folder, $respectNomediaAndNoimage, $hideImagesOnCustomMaps, $hideImagesInMapsFolder); $photoEntities = $this->photoMapper->findAllNonLocalized($userId, $limit, $offset); $suggestionsBySource = []; - $cache = $folder->getStorage()->getCache(); + $folder->getStorage()->getCache(); $previewEnableMimetypes = $this->getPreviewEnabledMimetypes(); - if (!is_null($timezone)) { - $tz = new \DateTimeZone($timezone); - } else { - $tz = new \DateTimeZone(\date_default_timezone_get()); - } + $tz = is_null($timezone) ? new \DateTimeZone(\date_default_timezone_get()) : new \DateTimeZone($timezone); + foreach ($photoEntities as $photoEntity) { // this path is relative to owner's storage //$path = $cacheEntry->getPath(); @@ -170,14 +176,16 @@ public function getNonLocalized(string $userId, ?Folder $folder = null, bool $re if ($file === null) { continue; } + $path = $userFolder->getRelativePath($file->getPath()); $isIgnored = false; foreach ($ignoredPaths as $ignoredPath) { - if (str_starts_with($path, $ignoredPath)) { + if (str_starts_with($path, (string)$ignoredPath)) { $isIgnored = true; break; } } + if (!$isIgnored) { $isRoot = $file === $userFolder; @@ -213,17 +221,19 @@ public function getNonLocalized(string $userId, ?Folder $folder = null, bool $re if (!array_key_exists($key, $suggestionsBySource)) { $suggestionsBySource[$key] = []; } + $suggestionsBySource[$key][] = $file_object; } } } + return $suggestionsBySource; } /** * @throws \OCP\Files\NotFoundException * @throws \OCP\Files\NotPermittedException - * @throws \OC\User\NoUserException + * @throws NoUserException */ private function getIgnoredPaths(string $userId, ?Folder $folder = null, bool $hideImagesOnCustomMaps = true): array { $ignoredPaths = []; @@ -231,6 +241,7 @@ private function getIgnoredPaths(string $userId, ?Folder $folder = null, bool $h if (is_null($folder)) { $folder = $userFolder; } + $ignoreFileMimetypes = [ 'application/x-nextcloud-noindex', 'application/x-nextcloud-nomedia', @@ -239,9 +250,8 @@ private function getIgnoredPaths(string $userId, ?Folder $folder = null, bool $h if ($hideImagesOnCustomMaps) { $ignoreFileMimetypes[] = 'application/x-nextcloud-maps'; } - $func = function (string $i): SearchComparison { - return new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', $i); - }; + + $func = (fn (string $i): SearchComparison => new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', $i)); $excludedNodes = $folder->search(new SearchQuery( new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, array_map( $func, @@ -254,6 +264,7 @@ private function getIgnoredPaths(string $userId, ?Folder $folder = null, bool $h foreach ($excludedNodes as $node) { $ignoredPaths[] = $userFolder->getRelativePath($node->getParent()->getPath()); } + return $ignoredPaths; } @@ -261,7 +272,6 @@ private function getIgnoredPaths(string $userId, ?Folder $folder = null, bool $h * returns a array of locations for a given date * * @param $dateTaken int - * @return array */ private function getLocationGuesses(int $dateTaken): array { $locations = []; @@ -271,6 +281,7 @@ private function getLocationGuesses(int $dateTaken): array { $locations[$key] = $location; } } + return $locations; } @@ -280,7 +291,7 @@ private function getLocationGuesses(int $dateTaken): array { * This function loads this Arrays from all Track files of the user. */ private function loadTimeorderedPointSets(string $userId, $folder = null, bool $respectNomediaAndNoimage = true, bool $hideTracksOnCustomMaps = false, bool $hideTracksInMapsFolder = true): void { - $key = $userId . ':' . (string)$respectNomediaAndNoimage . ':' . (string)$hideTracksOnCustomMaps . ':' . (string)$hideTracksInMapsFolder; + $key = $userId . ':' . $respectNomediaAndNoimage . ':' . $hideTracksOnCustomMaps . ':' . $hideTracksInMapsFolder; $this->timeorderedPointSets = $this->timeOrderedPointSetsCache->get($key); if (is_null($this->timeorderedPointSets)) { $userFolder = $this->getFolderForUser($userId); @@ -292,10 +303,12 @@ private function loadTimeorderedPointSets(string $userId, $folder = null, bool $ } } } + foreach ($this->devicesService->getDevicesFromDB($userId) as $device) { $device_points = $this->devicesService->getDeviceTimePointsFromDb($userId, $device['id']); $this->timeorderedPointSets['device:' . $device['id']] = $device_points; } + $this->timeOrderedPointSetsCache->set($key, $this->timeorderedPointSets); } } @@ -305,16 +318,21 @@ private function loadTimeorderedPointSets(string $userId, $folder = null, bool $ * @param $content * @return array */ + /** + * @return \SimpleXMLElement[] + */ private function getTracksFromGPX($content): array { $tracks = []; libxml_use_internal_errors(false); - $gpx = simplexml_load_string($content); + $gpx = simplexml_load_string((string)$content); if ($gpx === false) { $this->handleXMLError(); } + foreach ($gpx->trk as $trk) { $tracks[] = $trk; } + return $tracks; } @@ -338,42 +356,32 @@ private function getTimeorderdPointsFromTrack($track): array { $points = []; foreach ($track->trkseg as $seg) { foreach ($seg->trkpt as $pt) { - $points[strtotime($pt->time)] = [(string)$pt['lat'],(string)$pt['lon']]; + $points[strtotime((string)$pt->time)] = [(string)$pt['lat'],(string)$pt['lon']]; } } + foreach ($track->trkpt as $pt) { - $points[strtotime($pt->time)] = [(string)$pt['lat'],(string)$pt['lon']]; + $points[strtotime((string)$pt->time)] = [(string)$pt['lat'],(string)$pt['lon']]; } - $foo = ksort($points); + ksort($points); return $points; } - /** - * @param int $timeUTC - * @param float $lat - * @param float $lng - * @return void - */ - private function getLocalTime(int $timeUTC, float $lat, float $lng) { - - } - /** * @param $dateTaken int timestamp of the picture * @param $points array sorted by keys timestamp => [lat, lng] */ private function getLocationFromSequenceOfPoints(int $dateTaken, array $points): ?array { - $foo = end($points); - $end = key($points); - $foo = reset($points); - $start = key($points); - if ($start > $dateTaken or $end < $dateTaken) { + $end = array_key_last($points); + $start = array_key_first($points); + if ($start > $dateTaken || $end < $dateTaken) { return null; } + $smaller = null; $bigger = null; - foreach ($points as $time => $locations) { + foreach (array_keys($points) as $time) { if ($time < $dateTaken) { $smaller = $time; } else { @@ -381,17 +389,21 @@ private function getLocationFromSequenceOfPoints(int $dateTaken, array $points): break; } } - if (!is_null($smaller) and !is_null($bigger)) { + + if (!is_null($smaller) && !is_null($bigger)) { $d = $bigger - $smaller; $t = ($dateTaken - $smaller) / $d; $latd = $points[$bigger][0] - $points[$smaller][0]; $lngd = $points[$bigger][1] - $points[$smaller][1]; return [$points[$smaller][0] + $t * $latd, $points[$smaller][1] + $t * $lngd]; - } else { - return null; } + + return null; } + /** + * @return 'image/jpeg'[]|'image/tiff'[] + */ private function getPreviewEnabledMimetypes(): array { $enabledMimeTypes = []; foreach (PhotofilesService::PHOTO_MIME_TYPES as $mimeType) { @@ -399,6 +411,7 @@ private function getPreviewEnabledMimetypes(): array { $enabledMimeTypes[] = $mimeType; } } + return $enabledMimeTypes; } diff --git a/lib/Service/MimetypeService.php b/lib/Service/MimetypeService.php index fc42ccfa5..c7fcc0e38 100644 --- a/lib/Service/MimetypeService.php +++ b/lib/Service/MimetypeService.php @@ -1,5 +1,7 @@ mimeTypeLoader = $mimeTypeLoader; } - public function registerForExistingFiles() { + public function registerForExistingFiles(): void { $mimeTypeId = $this->mimeTypeLoader->getId('application/x-nextcloud-maps'); $this->mimeTypeLoader->updateFilecache('maps', $mimeTypeId); @@ -31,7 +33,7 @@ public function registerForExistingFiles() { $this->mimeTypeLoader->updateFilecache('notrack', $mimeTypeId); } - public function registerForNewFiles() { + public function registerForNewFiles(): void { $mapping = [ 'maps' => ['application/x-nextcloud-maps'], 'noindex' => ['application/x-nextcloud-noindex'], diff --git a/lib/Service/MyMapsService.php b/lib/Service/MyMapsService.php index 0308a2a0e..34f054e3b 100644 --- a/lib/Service/MyMapsService.php +++ b/lib/Service/MyMapsService.php @@ -1,5 +1,7 @@ root->getUserFolder($userId); if (!$userFolder->nodeExists('/Maps')) { $userFolder->newFolder('Maps'); } + if ($userFolder->nodeExists('/Maps')) { $mapsFolder = $userFolder->get('/Maps'); if (!($mapsFolder instanceof Folder)) { - $response = '/Maps is not a directory'; - return $response; - } elseif (!$mapsFolder->isCreatable()) { - $response = '/Maps is not writeable'; - return $response; + return '/Maps is not a directory'; + } + + if (!$mapsFolder->isCreatable()) { + return '/Maps is not writeable'; } } else { - $response = 'Impossible to create /Maps'; - return $response; - } - if ($counter > 0) { - $folderName = $newName . ' ' . $counter; - } else { - $folderName = $newName; + return 'Impossible to create /Maps'; } + $folderName = $counter > 0 ? $newName . ' ' . $counter : $newName; + if ($mapsFolder->nodeExists($folderName)) { return $this->addMyMap($newName, $userId, $counter + 1); } + $mapFolder = $mapsFolder->newFolder($folderName); $mapFolder->newFile('.index.maps', '{}'); + $isRoot = $mapFolder->getPath() === $userFolder->getPath(); - $MyMap = [ + return [ 'id' => $mapFolder->getId(), 'name' => $folderName, 'color' => null, @@ -85,23 +83,23 @@ public function addMyMap($newName, $userId, $counter = 0) { 'sharePermissions' => $mapFolder->getPermissions(), ] ]; - return $MyMap; } + /** + * @return array + */ private function node2MyMap($node, $userFolder):array { - $mapData = json_decode($node->getContent(), true); - if (isset($mapData['name'])) { - $name = $mapData['name']; - } else { - $name = $node->getParent()->getName(); - } + $mapData = json_decode((string)$node->getContent(), true); + $name = $mapData['name'] ?? $node->getParent()->getName(); + $color = null; if (isset($mapData['color'])) { $color = $mapData['color']; } + $parentNode = $node->getParent(); $isRoot = $parentNode->getPath() === $userFolder->getPath(); - $MyMap = [ + return [ 'id' => $parentNode->getId(), 'name' => $name, 'color' => $color, @@ -125,16 +123,14 @@ private function node2MyMap($node, $userFolder):array { 'sharePermissions' => $parentNode->getPermissions(), ] ]; - return $MyMap; } /** * @param $userId - * @return array * @throws NoUserException * @throws NotPermittedException */ - public function getAllMyMaps($userId) { + public function getAllMyMaps($userId): array { $userFolder = $this->root->getUserFolder($userId); $MyMaps = []; $MyMapsNodes = $userFolder->search(new SearchQuery( @@ -146,6 +142,7 @@ public function getAllMyMaps($userId) { $MyMaps[] = $this->node2MyMap($node, $userFolder); } } + return $MyMaps; } @@ -156,7 +153,7 @@ public function getAllMyMaps($userId) { * @param string $userId The current user id * @return null|array Either the MyMap or null if not found with that id for the given user */ - public function getMyMap(int $id, string $userId) { + public function getMyMap(int $id, string $userId): ?array { $userFolder = $this->root->getUserFolder($userId); $node = $userFolder->getFirstNodeById($id); if ($node instanceof Folder) { @@ -170,6 +167,7 @@ public function getMyMap(int $id, string $userId) { if ($node->getMimetype() === 'application/x-nextcloud-maps') { return $this->node2MyMap($node, $userFolder); } + return null; } @@ -179,13 +177,15 @@ public function updateMyMap($id, $values, $userId) { if (!($folder instanceof Folder)) { return []; } + try { /** @var File $file */ $file = $folder->get('.index.maps'); - } catch (NotFoundException $e) { + } catch (NotFoundException) { $file = $folder->newFile('.index.maps', '{}'); } - $mapData = json_decode($file->getContent(), true); + + $mapData = json_decode((string)$file->getContent(), true); $renamed = false; foreach ($values as $key => $value) { if ($key === 'newName') { @@ -193,57 +193,61 @@ public function updateMyMap($id, $values, $userId) { $newName = $value; $renamed = true; } + if (is_null($value)) { unset($mapData[$key]); } else { $mapData[$key] = $value; } } + $file->putContent(json_encode($mapData, JSON_PRETTY_PRINT)); - if ($renamed) { - if ($userFolder->nodeExists('/Maps')) { - $mapsFolder = $userFolder->get('/Maps'); - if ($folder->getParent()->getId() === $mapsFolder->getId()) { - try { - $folder->move($mapsFolder->getPath() . '/' . $newName); - } catch (\Exception $e) { - } + if ($renamed && $userFolder->nodeExists('/Maps')) { + $mapsFolder = $userFolder->get('/Maps'); + if ($folder->getParent()->getId() === $mapsFolder->getId()) { + try { + $folder->move($mapsFolder->getPath() . '/' . $newName); + } catch (\Exception) { } } } + return $mapData; } - public function deleteMyMap($id, $userId) { + public function deleteMyMap($id, $userId): int { $userFolder = $this->root->getUserFolder($userId); $folder = $userFolder->getFirstNodeById($id); if (!($folder instanceof Folder)) { return 1; } + if ($userFolder->nodeExists('/Maps')) { $mapsFolder = $userFolder->get('/Maps'); if ($folder->getParent()->getId() === $mapsFolder->getId()) { try { $folder->delete(); - } catch (\Exception $e) { + } catch (\Exception) { return 1; } } else { try { $file = $folder->get('.index.maps'); $file->delete(); - } catch (\Exception $e) { + } catch (\Exception) { return 1; } } } + try { $file = $folder->get('.index.maps'); $file->delete(); - } catch (NotFoundException $e) { + } catch (NotFoundException) { return 1; } + return 0; } diff --git a/lib/Service/PhotofilesService.php b/lib/Service/PhotofilesService.php index 8a3dbc5bb..b4247c372 100644 --- a/lib/Service/PhotofilesService.php +++ b/lib/Service/PhotofilesService.php @@ -1,5 +1,7 @@ * @copyright Piotr Bator 2017 */ - namespace OCA\Maps\Service; use OCA\Maps\BackgroundJob\AddPhotoJob; @@ -25,6 +26,8 @@ use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\Node; +use OCP\Files\StorageNotAvailableException; +use OCP\ICache; use OCP\ICacheFactory; use OCP\IL10N; use OCP\Share\IManager; @@ -45,27 +48,29 @@ class PhotofilesService { public const PHOTO_MIME_TYPES = ['image/jpeg', 'image/tiff']; - private $l10n; private $root; - private $photoMapper; + + private $shareManager; + private $jobList; - private ICacheFactory $cacheFactory; - private \OCP\ICache $photosCache; - private \OCP\ICache $backgroundJobCache; + + private readonly ICacheFactory $cacheFactory; + + private readonly ICache $photosCache; + + private readonly ICache $backgroundJobCache; public function __construct( - private LoggerInterface $logger, + private readonly LoggerInterface $logger, ICacheFactory $cacheFactory, IRootFolder $root, IL10N $l10n, - GeophotoMapper $photoMapper, + private readonly GeophotoMapper $photoMapper, IManager $shareManager, IJobList $jobList, ) { $this->root = $root; - $this->l10n = $l10n; - $this->photoMapper = $photoMapper; $this->shareManager = $shareManager; $this->jobList = $jobList; $this->cacheFactory = $cacheFactory; @@ -73,7 +78,10 @@ public function __construct( $this->backgroundJobCache = $this->cacheFactory->createDistributed('maps:background-jobs'); } - public function rescan($userId, $inBackground = true, $pathToScan = null) { + /** + * @psalm-return \Generator + */ + public function rescan($userId, $inBackground = true, $pathToScan = null): \Generator { $this->photosCache->clear($userId); $userFolder = $this->root->getUserFolder($userId); if ($pathToScan === null) { @@ -82,6 +90,7 @@ public function rescan($userId, $inBackground = true, $pathToScan = null) { } else { $folder = $userFolder->get($pathToScan); } + $photos = $this->gatherPhotoFiles($folder, true); foreach ($photos as $photo) { if ($inBackground) { @@ -89,13 +98,14 @@ public function rescan($userId, $inBackground = true, $pathToScan = null) { } else { $this->addPhotoNow($photo, $userId); } + yield $photo->getPath(); } } // add the file for its owner and users that have access // check if it's already in DB before adding - public function addByFile(Node $file) { + public function addByFile(Node $file): bool { if ($this->isPhoto($file)) { $ownerId = $file->getOwner()->getUID(); $this->addPhoto($file, $ownerId); @@ -108,16 +118,17 @@ public function addByFile(Node $file) { } } } + return true; - } else { - return false; } + + return false; } public function addByFileIdUserId(int $fileId, string $userId): void { $userFolder = $this->root->getUserFolder($userId); $file = $userFolder->getFirstNodeById($fileId); - if ($file instanceof File and $this->isPhoto($file)) { + if ($file instanceof File && $this->isPhoto($file)) { $this->addPhoto($file, $userId); } } @@ -140,7 +151,7 @@ public function addByFolder(Folder $folder): void { } } - public function updateByFile(Node $file) { + public function updateByFile(Node $file): void { $this->jobList->add(UpdatePhotoByFileJob::class, ['fileId' => $file->getId(), 'userId' => $file->getOwner()->getUID()]); } @@ -154,7 +165,7 @@ public function updateByFileNow(File $file): void { $this->photoMapper->findByFileIdUserId($file->getId(), $ownerId); $this->updatePhoto($file, $exif); $this->photosCache->clear($ownerId); - } catch (DoesNotExistException $exception) { + } catch (DoesNotExistException) { $this->insertPhoto($file, $ownerId, $exif); } } @@ -185,7 +196,7 @@ public function deleteByFolder(Folder $folder): void { } // delete folder photos only if it's not accessible to user anymore - public function deleteByFolderIdUserId($folderId, $userId) { + public function deleteByFolderIdUserId($folderId, $userId): void { $userFolder = $this->root->getUserFolder($userId); $folders = $userFolder->getById($folderId); if (is_array($folders) && count($folders) === 1) { @@ -194,12 +205,13 @@ public function deleteByFolderIdUserId($folderId, $userId) { foreach ($photos as $photo) { $this->photoMapper->deleteByFileIdUserId($photo->getId(), $userId); } + $this->photosCache->clear($userId); } } /** - * @return array + * @return array */ public function getBackgroundJobStatus(string $userId): array { $add_counter = 0; @@ -209,8 +221,10 @@ public function getBackgroundJobStatus(string $userId): array { if ($job->getArgument()['userId'] === $userId) { $add_counter += 1; } + $addJobsRunning = true; } + $update_counter = 0; $updateJobsRunning = false; @@ -218,8 +232,10 @@ public function getBackgroundJobStatus(string $userId): array { if ($job->getArgument()['userId'] === $userId) { $update_counter += 1; } + $updateJobsRunning = true; } + $recentlyAdded = $this->backgroundJobCache->get('recentlyAdded:' . $userId) ?? 0; $recentlyUpdated = $this->backgroundJobCache->get('$recentlyUpdated:' . $userId) ?? 0; return [ @@ -232,12 +248,12 @@ public function getBackgroundJobStatus(string $userId): array { ]; } - public function setPhotosFilesCoords(string $userId, $paths, $lats, $lngs, $directory) { + public function setPhotosFilesCoords(string $userId, $paths, $lats, $lngs, $directory): array { if ($directory) { return $this->setDirectoriesCoords($userId, $paths, $lats, $lngs); - } else { - return $this->setFilesCoords($userId, $paths, $lats, $lngs); } + + return $this->setFilesCoords($userId, $paths, $lats, $lngs); } private function setDirectoriesCoords(string $userId, $paths, $lats, $lngs): array { @@ -255,7 +271,7 @@ private function setDirectoriesCoords(string $userId, $paths, $lats, $lngs): arr if ($this->isPhoto($node) && $node->isUpdateable()) { $photo = $this->photoMapper->findByFileIdUserId($node->getId(), $userId); $done[] = [ - 'path' => preg_replace('/^files/', '', $node->getInternalPath()), + 'path' => preg_replace('/^files/', '', (string)$node->getInternalPath()), 'lat' => $lat, 'lng' => $lng, 'oldLat' => $photo ? $photo->getLat() : null, @@ -268,10 +284,14 @@ private function setDirectoriesCoords(string $userId, $paths, $lats, $lngs): arr } } } + return $done; } - private function setFilesCoords($userId, $paths, $lats, $lngs) { + /** + * @return array{path: (array | string | null), lat: mixed, lng: mixed, oldLat: mixed, oldLng: mixed}[] + */ + private function setFilesCoords(string $userId, $paths, array $lats, array $lngs): array { $userFolder = $this->root->getUserFolder($userId); $done = []; @@ -287,6 +307,7 @@ private function setFilesCoords($userId, $paths, $lats, $lngs) { } catch (DoesNotExistException) { $photo = null; } + $done[] = [ 'path' => preg_replace('/^files/', '', $file->getInternalPath()), 'lat' => $lat, @@ -299,21 +320,25 @@ private function setFilesCoords($userId, $paths, $lats, $lngs) { } } } + return $done; } - public function resetPhotosFilesCoords($userId, $paths) { + /** + * @return array{path: (array | string | null), lat: null, lng: null, oldLat: mixed, oldLng: mixed}[] + */ + public function resetPhotosFilesCoords($userId, $paths): array { $userFolder = $this->root->getUserFolder($userId); $done = []; - foreach ($paths as $i => $path) { + foreach ($paths as $path) { $cleanpath = str_replace(['../', '..\\'], '', $path); if ($userFolder->nodeExists($cleanpath)) { $file = $userFolder->get($cleanpath); if ($this->isPhoto($file) && $file->isUpdateable()) { $photo = $this->photoMapper->findByFileIdUserId($file->getId(), $userId); $done[] = [ - 'path' => preg_replace('/^files/', '', $file->getInternalPath()), + 'path' => preg_replace('/^files/', '', (string)$file->getInternalPath()), 'lat' => null, 'lng' => null, 'oldLat' => $photo ? $photo->getLat() : null, @@ -324,6 +349,7 @@ public function resetPhotosFilesCoords($userId, $paths) { } } } + return $done; } @@ -332,7 +358,7 @@ private function addPhoto($photo, string $userId): void { $this->jobList->add(AddPhotoJob::class, ['photoId' => $photo->getId(), 'userId' => $userId]); } - public function addPhotoNow($photo, $userId) { + public function addPhotoNow($photo, $userId): void { $exif = $this->getExif($photo); if (!is_null($exif)) { // filehooks are triggered several times (2 times for file creation) @@ -341,15 +367,16 @@ public function addPhotoNow($photo, $userId) { // OR by using file_id in primary key try { $this->photoMapper->findByFileIdUserId($photo->getId(), $userId); - } catch (DoesNotExistException $exception) { + } catch (DoesNotExistException) { $this->insertPhoto($photo, $userId, $exif); } + $this->photosCache->clear($userId); } } - private function insertPhoto($photo, $userId, $exif) { + private function insertPhoto($photo, $userId, ExifGeoData $exif): void { $photoEntity = new Geophoto(); $photoEntity->setFileId($photo->getId()); $photoEntity->setLat( @@ -361,18 +388,19 @@ private function insertPhoto($photo, $userId, $exif) { $photoEntity->setUserId($userId); // alternative should be file creation date $photoEntity->setDateTaken($exif->dateTaken ?? $photo->getMTime()); + $this->photoMapper->insert($photoEntity); $this->photosCache->clear($userId); } - private function updatePhoto(File $file, $exif): void { + private function updatePhoto(File $file, ExifGeoData $exif): void { $lat = is_numeric($exif->lat) && !is_nan($exif->lat) ? $exif->lat : null; $lng = is_numeric($exif->lng) && !is_nan($exif->lng) ? $exif->lng : null; $this->photoMapper->updateByFileId($file->getId(), $lat, $lng); } - private function normalizePath($node) { + private function normalizePath($node): string|array { return str_replace('files', '', $node->getInternalPath()); } @@ -381,11 +409,14 @@ public function getPhotosByFolder(string $userId, string $path): array { $folder = $userFolder->get($path); if ($folder instanceof Folder) { return $this->getPhotosListForFolder($folder); - } else { - return []; } + + return []; } + /** + * @return \stdClass[] + */ private function getPhotosListForFolder(Folder $folder): array { $FilesList = $this->gatherPhotoFiles($folder, false); $notes = []; @@ -395,6 +426,7 @@ private function getPhotosListForFolder(Folder $folder): array { $file_object->path = $this->normalizePath($File); $notes[] = $file_object; } + return $notes; } @@ -410,19 +442,23 @@ private function gatherPhotoFiles(Folder $folder, bool $recursive): array { continue; } } + try { $notes = array_merge($notes, $this->gatherPhotoFiles($node, $recursive)); - } catch (\OCP\Files\StorageNotAvailableException|\Exception $e) { + } catch (StorageNotAvailableException|\Exception) { $msg = 'WARNING: Could not access ' . $node->getName(); echo($msg . "\n"); $this->logger->error($msg); } + continue; } + if ($this->isPhoto($node)) { $notes[] = $node; } } + return $notes; } @@ -433,6 +469,7 @@ private function isPhoto(Node $file): bool { if ($file instanceof File) { return false; } + return in_array($file->getMimetype(), self::PHOTO_MIME_TYPES); } @@ -441,7 +478,6 @@ private function isPhoto(Node $file): bool { * returns with null in any validation or Critical errors * * @param $file - * @return ExifGeoData|null */ private function getExif($file) : ?ExifGeoData { $path = $file->getStorage()->getLocalFile($file->getInternalPath()); @@ -457,10 +493,11 @@ private function getExif($file) : ?ExifGeoData { $exif_geo_data = null; $this->logger->error($f->getMessage(), ['code' => $f->getCode(), 'path' => $path]); } + return $exif_geo_data; } - private function resetExifCoords($file) { + private function resetExifCoords($file): void { $data = new PelDataWindow($file->getContent()); $pelJpeg = new PelJpeg($data); @@ -518,7 +555,7 @@ private function setExifCoords(File $file, $lat, $lng): void { $file->putContent($pelJpeg->getBytes()); } - private function setGeolocation($pelSubIfdGps, $latitudeDegreeDecimal, $longitudeDegreeDecimal) { + private function setGeolocation(PelIfd $pelSubIfdGps, $latitudeDegreeDecimal, $longitudeDegreeDecimal): void { $latitudeRef = ($latitudeDegreeDecimal >= 0) ? 'N' : 'S'; $latitudeDegreeMinuteSecond = $this->degreeDecimalToDegreeMinuteSecond(abs($latitudeDegreeDecimal)); @@ -551,7 +588,7 @@ private function setGeolocation($pelSubIfdGps, $latitudeDegreeDecimal, $longitud /** * @return array{degree: float, minute: float, second: float} */ - private function degreeDecimalToDegreeMinuteSecond($degreeDecimal): array { + private function degreeDecimalToDegreeMinuteSecond(float|int $degreeDecimal): array { $degree = floor($degreeDecimal); $remainder = $degreeDecimal - $degree; $minute = floor($remainder * 60); diff --git a/lib/Service/TracksService.php b/lib/Service/TracksService.php index 21fc4a120..a7315ca80 100644 --- a/lib/Service/TracksService.php +++ b/lib/Service/TracksService.php @@ -1,5 +1,7 @@ + */ + public function rescan($userId): \Generator { $userFolder = $this->root->getUserFolder($userId); $tracks = $this->gatherTrackFiles($userFolder, true); $this->deleteAllTracksFromDB($userId); @@ -51,7 +55,7 @@ public function rescan($userId) { } public function addByFile(Node $file): void { - $userFolder = $this->root->getUserFolder($file->getOwner()->getUID()); + $this->root->getUserFolder($file->getOwner()->getUID()); if ($this->isTrack($file)) { $this->addTrackToDB($file->getOwner()->getUID(), $file->getId(), $file); } @@ -73,6 +77,7 @@ public function safeAddByFile(File $file): bool { $this->safeAddTrack($file, $uid); } } + return true; } @@ -82,6 +87,7 @@ public function safeAddByFileIdUserId(int $fileId, string $userId): void { if ($file === null || !$this->isTrack($file)) { return; } + $this->safeAddTrack($file, $userId); } @@ -90,6 +96,7 @@ public function safeAddByFolderIdUserId(int $folderId, string $userId): void { if ($folder === null) { return; } + $tracks = $this->gatherTrackFiles($folder, true); foreach ($tracks as $track) { $this->safeAddTrack($track, $userId); @@ -147,7 +154,7 @@ public function deleteByFolder(Folder $folder): void { public function safeDeleteByFolderIdUserId(int $folderId, string $userId): void { $userFolder = $this->root->getUserFolder($userId); $folders = $userFolder->getById($folderId); - if (is_array($folders) and count($folders) === 1) { + if (is_array($folders) && count($folders) === 1) { $folder = array_shift($folders); $tracks = $this->gatherTrackFiles($folder, true); foreach ($tracks as $track) { @@ -166,17 +173,20 @@ private function gatherTrackFiles(Folder $folder, bool $recursive): array { if ($node instanceof Folder && $recursive) { try { $notes = array_merge($notes, $this->gatherTrackFiles($node, $recursive)); - } catch (\OCP\Files\StorageNotAvailableException|\Exception $e) { + } catch (StorageNotAvailableException|\Exception) { $msg = 'WARNING: Could not access ' . $node->getName(); echo($msg . "\n"); $this->logger->error($msg); } + continue; } + if ($this->isTrack($node)) { $notes[] = $node; } } + return $notes; } @@ -184,33 +194,41 @@ private function isTrack(Node $file): bool { if (!$file instanceof File) { return false; } + return in_array($file->getMimetype(), self::TRACK_MIME_TYPES); } - private function dbRowToTrack($row, Folder $folder, $userFolder, $defaultMap, $ignoredPaths) { + /** + * @param array $row + */ + private function dbRowToTrack(array $row, Folder $folder, $userFolder, bool $defaultMap, array $ignoredPaths): ?array { // avoid tracks that are not in "this map's" folder $file = $folder->getFirstNodeById(intval($row['file_id'])); if ($file === null) { if ($defaultMap) { $this->deleteTrackFromDB($row['id']); } + return null; } + if (!$file instanceof File) { if ($defaultMap) { $this->deleteTrackFromDB($row['id']); } + return null; } $path = $userFolder->getRelativePath($file->getPath()); $isIgnored = false; foreach ($ignoredPaths as $ignoredPath) { - if (str_starts_with($path, $ignoredPath)) { + if (str_starts_with((string)$path, (string)$ignoredPath)) { $isIgnored = true; break; } } + if ($isIgnored) { return null; } @@ -233,11 +251,15 @@ private function dbRowToTrack($row, Folder $folder, $userFolder, $defaultMap, $i } - public function getTracksFromDB(string $userId, $folder = null, bool $respectNomediaAndNoimage = true, bool $hideTracksOnCustomMaps = false, bool $hideTracksInMapsFolder = true) { + /** + * @return mixed[] + */ + public function getTracksFromDB(string $userId, $folder = null, bool $respectNomediaAndNoimage = true, bool $hideTracksOnCustomMaps = false, bool $hideTracksInMapsFolder = true): array { $ignoredPaths = $respectNomediaAndNoimage ? $this->getIgnoredPaths($userId, $folder, $hideTracksOnCustomMaps) : []; if ($hideTracksInMapsFolder) { $ignoredPaths[] = '/Maps'; } + $userFolder = $this->root->getUserFolder($userId); $tracks = []; $qb = $this->dbconnection->getQueryBuilder(); @@ -251,6 +273,7 @@ public function getTracksFromDB(string $userId, $folder = null, bool $respectNom if (is_null($folder)) { $folder = $userFolder; } + $defaultMap = $folder->getId() === $userFolder->getId(); // my-maps context @@ -259,8 +282,10 @@ public function getTracksFromDB(string $userId, $folder = null, bool $respectNom if (is_null($track)) { continue; } + $tracks[] = $track; } + $req->closeCursor(); return $tracks; } @@ -268,17 +293,17 @@ public function getTracksFromDB(string $userId, $folder = null, bool $respectNom /** * @param $userId * @param $folder - * @return array * @throws \OCP\Files\NotFoundException * @throws \OCP\Files\NotPermittedException - * @throws \OC\User\NoUserException + * @throws NoUserException */ - private function getIgnoredPaths($userId, $folder = null, $hideImagesOnCustomMaps = true) { + private function getIgnoredPaths(string $userId, $folder = null, bool $hideImagesOnCustomMaps = true): array { $ignoredPaths = []; $userFolder = $this->root->getUserFolder($userId); if (is_null($folder)) { $folder = $userFolder; } + $ignoreFileMimetypes = [ 'application/x-nextcloud-noindex', 'application/x-nextcloud-nomedia', @@ -287,9 +312,8 @@ private function getIgnoredPaths($userId, $folder = null, $hideImagesOnCustomMap if ($hideImagesOnCustomMaps) { $ignoreFileMimetypes[] = 'application/x-nextcloud-maps'; } - $func = function (string $i): SearchComparison { - return new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', $i); - }; + + $func = (fn (string $i): SearchComparison => new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', $i)); $excludedNodes = $folder->search(new SearchQuery( new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, array_map( $func, @@ -302,10 +326,11 @@ private function getIgnoredPaths($userId, $folder = null, $hideImagesOnCustomMap foreach ($excludedNodes as $node) { $ignoredPaths[] = $userFolder->getRelativePath($node->getParent()->getPath()); } + return $ignoredPaths; } - public function getTrackFromDB(int $id, ?string $userId = null) { + public function getTrackFromDB(int $id, ?string $userId = null): ?array { $track = null; $qb = $this->dbconnection->getQueryBuilder(); $qb->select('id', 'file_id', 'color', 'metadata', 'etag') @@ -318,15 +343,17 @@ public function getTrackFromDB(int $id, ?string $userId = null) { $qb->expr()->eq('user_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)) ); } + $req = $qb->executeQuery(); while ($row = $req->fetch()) { - if ($userId !== '' and $userId !== null) { + if ($userId !== '' && $userId !== null) { $userFolder = $this->root->getUserFolder($userId); $file = $userFolder->getFirstNodeById(intval($row['file_id'])); if ($file === null) { break; } + $track = $this->dbRowToTrack($row, $userFolder, $userFolder, true, []); } else { $track = [ @@ -345,13 +372,15 @@ public function getTrackFromDB(int $id, ?string $userId = null) { 'file_path' => '', ]; } + break; } + $req->closeCursor(); return $track; } - public function getTrackByFileIDFromDB(int $fileId, ?string $userId = null) { + public function getTrackByFileIDFromDB(int $fileId, ?string $userId = null): ?array { $track = null; $qb = $this->dbconnection->getQueryBuilder(); $qb->select('id', 'file_id', 'color', 'metadata', 'etag') @@ -364,15 +393,17 @@ public function getTrackByFileIDFromDB(int $fileId, ?string $userId = null) { $qb->expr()->eq('user_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)) ); } + $req = $qb->executeQuery(); while ($row = $req->fetch()) { - if ($userId !== '' and $userId !== null) { + if ($userId !== '' && $userId !== null) { $userFolder = $this->root->getUserFolder($userId); $file = $userFolder->getFirstNodeById(intval($row['file_id'])); if ($file === null) { break; } + $track = $this->dbRowToTrack($row, $userFolder, $userFolder, true, []); } else { $track = [ @@ -391,13 +422,15 @@ public function getTrackByFileIDFromDB(int $fileId, ?string $userId = null) { 'file_path' => '', ]; } + break; } + $req->closeCursor(); return $track; } - public function addTrackToDB($userId, $fileId, $file) { + public function addTrackToDB($userId, $fileId, $file): int { $metadata = ''; $etag = $file->getEtag(); $qb = $this->dbconnection->getQueryBuilder(); @@ -409,8 +442,7 @@ public function addTrackToDB($userId, $fileId, $file) { 'etag' => $qb->createNamedParameter($etag, IQueryBuilder::PARAM_STR) ]); $qb->executeStatement(); - $trackId = $qb->getLastInsertId(); - return $trackId; + return $qb->getLastInsertId(); } public function editTrackInDB(int $id, ?string $color, ?string $metadata, ?string $etag): void { @@ -419,12 +451,15 @@ public function editTrackInDB(int $id, ?string $color, ?string $metadata, ?strin if ($color !== null) { $qb->set('color', $qb->createNamedParameter($color, IQueryBuilder::PARAM_STR)); } + if ($metadata !== null) { $qb->set('metadata', $qb->createNamedParameter($metadata, IQueryBuilder::PARAM_STR)); } + if ($etag !== null) { $qb->set('etag', $qb->createNamedParameter($etag, IQueryBuilder::PARAM_STR)); } + $qb->where( $qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)) ); @@ -471,7 +506,7 @@ public function deleteAllTracksFromDB(string $userId): void { } public function deleteTracksFromDB(array $ids, string $userId): void { - if (empty($ids)) { + if ($ids === []) { return; } @@ -484,8 +519,7 @@ public function deleteTracksFromDB(array $ids, string $userId): void { $qb->executeStatement(); } - public function generateTrackMetadata($file) { - $DISTANCE_BETWEEN_SHORT_POINTS = 300; + public function generateTrackMetadata($file): ?string { $STOPPED_SPEED_THRESHOLD = 0.9; $name = $file->getName(); @@ -497,8 +531,6 @@ public function generateTrackMetadata($file) { $total_duration = 0; $date_begin = null; $date_end = null; - - $distAccCumulEle = 0; $pos_elevation = 0; $neg_elevation = 0; $min_elevation = null; @@ -508,7 +540,6 @@ public function generateTrackMetadata($file) { $moving_time = 0; $moving_distance = 0; $stopped_distance = 0; - $moving_max_speed = 0; $moving_avg_speed = 0; $stopped_time = 0; $north = null; @@ -524,15 +555,15 @@ public function generateTrackMetadata($file) { try { $gpx = new \SimpleXMLElement($gpx_content); - } catch (\Throwable $e) { + } catch (\Throwable $throwable) { $this->logger->error( - 'Exception in ' . $name . ' gpx parsing : ' . $e->getMessage(), + 'Exception in ' . $name . ' gpx parsing : ' . $throwable->getMessage(), ['app' => 'maps'] ); return null; } - if (count($gpx->trk) === 0 and count($gpx->rte) === 0 and count($gpx->wpt) === 0) { + if (count($gpx->trk) === 0 && count($gpx->rte) === 0 && count($gpx->wpt) === 0) { $this->logger->error( 'Nothing to parse in ' . $name . ' gpx file', ['app' => 'maps'] @@ -541,7 +572,7 @@ public function generateTrackMetadata($file) { } // METADATA - if (!empty($gpx->metadata) and !empty($gpx->metadata->link)) { + if (!empty($gpx->metadata) && !empty($gpx->metadata->link)) { $linkurl = $gpx->metadata->link['href']; if (!empty($gpx->metadata->link->text)) { $linktext = $gpx->metadata->link->text; @@ -550,10 +581,11 @@ public function generateTrackMetadata($file) { // TRACKS foreach ($gpx->trk as $track) { - $trackname = str_replace("\n", '', $track->name); + $trackname = str_replace("\n", '', (string)$track->name); if (empty($trackname)) { $trackname = ''; } + $trackname = str_replace('"', "'", $trackname); $trackNameList[] = sprintf('"%s"', $trackname); foreach ($track->trkseg as $segment) { @@ -562,44 +594,36 @@ public function generateTrackMetadata($file) { $pointIndex = 0; $pointsBySegment[] = $segment->trkpt; foreach ($segment->trkpt as $point) { - if (empty($point['lat']) or empty($point['lon'])) { + if (empty($point['lat'])) { continue; } - if (empty($point->ele)) { - $pointele = null; - } else { - $pointele = floatval($point->ele); - } - if (empty($point->time)) { - $pointtime = null; - } else { - $pointtime = new \DateTime($point->time); - } - if ($lastPoint !== null and (!empty($lastPoint->ele))) { - $lastPointele = floatval($lastPoint->ele); - } else { - $lastPointele = null; - } - if ($lastPoint !== null and (!empty($lastPoint->time))) { - $lastTime = new \DateTime($lastPoint->time); - } else { - $lastTime = null; - } - if ($lastPoint !== null) { - $distToLast = distance($lastPoint, $point); - } else { - $distToLast = null; + + if (empty($point['lon'])) { + continue; } + + $pointele = empty($point->ele) ? null : floatval($point->ele); + + $pointtime = empty($point->time) ? null : new \DateTime((string)$point->time); + + $lastPointele = ($lastPoint !== null && !empty($lastPoint->ele)) ? floatval($lastPoint->ele) : null; + + $lastTime = ($lastPoint !== null && !empty($lastPoint->time)) ? new \DateTime((string)$lastPoint->time) : null; + + $distToLast = $lastPoint !== null ? distance((array)$lastPoint, (array)$point) : null; + $pointlat = floatval($point['lat']); $pointlon = floatval($point['lon']); if ($pointIndex === 0) { - if ($lat === '0' and $lon === '0') { + if ($lat === '0' && $lon === '0') { $lat = $pointlat; $lon = $pointlon; } - if ($pointtime !== null and ($date_begin === null or $pointtime < $date_begin)) { + + if ($pointtime instanceof \DateTime && (!$date_begin instanceof \DateTime || $pointtime < $date_begin)) { $date_begin = $pointtime; } + $downBegin = $pointele; if ($north === null) { $north = $pointlat; @@ -612,29 +636,35 @@ public function generateTrackMetadata($file) { if ($pointlat > $north) { $north = $pointlat; } + if ($pointlat < $south) { $south = $pointlat; } + if ($pointlon > $east) { $east = $pointlon; } + if ($pointlon < $west) { $west = $pointlon; } - if ($pointele !== null and ($min_elevation === null or $pointele < $min_elevation)) { + + if ($pointele !== null && ($min_elevation === null || $pointele < $min_elevation)) { $min_elevation = $pointele; } - if ($pointele !== null and ($max_elevation === null or $pointele > $max_elevation)) { + + if ($pointele !== null && ($max_elevation === null || $pointele > $max_elevation)) { $max_elevation = $pointele; } - if ($lastPoint !== null and $pointtime !== null and $lastTime !== null) { + + if ($lastPoint !== null && $pointtime instanceof \DateTime && $lastTime instanceof \DateTime) { $t = abs($lastTime->getTimestamp() - $pointtime->getTimestamp()); $speed = 0; if ($t > 0) { $speed = $distToLast / $t; - $speed = $speed / 1000; - $speed = $speed * 3600; + $speed /= 1000; + $speed *= 3600; } if ($speed <= $STOPPED_SPEED_THRESHOLD) { @@ -645,6 +675,7 @@ public function generateTrackMetadata($file) { $moving_distance += $distToLast; } } + if ($lastPoint !== null) { $total_distance += $distToLast; } @@ -653,7 +684,7 @@ public function generateTrackMetadata($file) { $pointIndex += 1; } - if ($lastTime !== null and ($date_end === null or $lastTime > $date_end)) { + if ($lastTime instanceof \DateTime && ($date_end === null || $lastTime > $date_end)) { $date_end = $lastTime; } } @@ -666,6 +697,7 @@ public function generateTrackMetadata($file) { if (empty($routename)) { $routename = ''; } + $routename = str_replace('"', "'", $routename); $trackNameList[] = sprintf('"%s"', $routename); @@ -674,44 +706,36 @@ public function generateTrackMetadata($file) { $pointIndex = 0; $pointsBySegment[] = $route->rtept; foreach ($route->rtept as $point) { - if (empty($point['lat']) or empty($point['lon'])) { + if (empty($point['lat'])) { continue; } - if (empty($point->ele)) { - $pointele = null; - } else { - $pointele = floatval($point->ele); - } - if (empty($point->time)) { - $pointtime = null; - } else { - $pointtime = new \DateTime($point->time); - } - if ($lastPoint !== null and (!empty($lastPoint->ele))) { - $lastPointele = floatval($lastPoint->ele); - } else { - $lastPointele = null; - } - if ($lastPoint !== null and (!empty($lastPoint->time))) { - $lastTime = new \DateTime($lastPoint->time); - } else { - $lastTime = null; - } - if ($lastPoint !== null) { - $distToLast = distance($lastPoint, $point); - } else { - $distToLast = null; + + if (empty($point['lon'])) { + continue; } + + $pointele = empty($point->ele) ? null : floatval($point->ele); + + $pointtime = empty($point->time) ? null : new \DateTime((string)$point->time); + + $lastPointele = ($lastPoint !== null && !empty($lastPoint->ele)) ? floatval($lastPoint->ele) : null; + + $lastTime = ($lastPoint !== null && !empty($lastPoint->time)) ? new \DateTime((string)$lastPoint->time) : null; + + $distToLast = $lastPoint !== null ? distance((array)$lastPoint, (array)$point) : null; + $pointlat = floatval($point['lat']); $pointlon = floatval($point['lon']); if ($pointIndex === 0) { - if ($lat === '0' and $lon === '0') { + if ($lat === '0' && $lon === '0') { $lat = $pointlat; $lon = $pointlon; } - if ($pointtime !== null and ($date_begin === null or $pointtime < $date_begin)) { + + if ($pointtime instanceof \DateTime && (!$date_begin instanceof \DateTime || $pointtime < $date_begin)) { $date_begin = $pointtime; } + $downBegin = $pointele; if ($north === null) { $north = $pointlat; @@ -724,29 +748,35 @@ public function generateTrackMetadata($file) { if ($pointlat > $north) { $north = $pointlat; } + if ($pointlat < $south) { $south = $pointlat; } + if ($pointlon > $east) { $east = $pointlon; } + if ($pointlon < $west) { $west = $pointlon; } - if ($pointele !== null and ($min_elevation === null or $pointele < $min_elevation)) { + + if ($pointele !== null && ($min_elevation === null || $pointele < $min_elevation)) { $min_elevation = $pointele; } - if ($pointele !== null and ($max_elevation === null or $pointele > $max_elevation)) { + + if ($pointele !== null && ($max_elevation === null || $pointele > $max_elevation)) { $max_elevation = $pointele; } - if ($lastPoint !== null and $pointtime !== null and $lastTime !== null) { + + if ($lastPoint !== null && $pointtime instanceof \DateTime && $lastTime instanceof \DateTime) { $t = abs($lastTime->getTimestamp() - $pointtime->getTimestamp()); $speed = 0; if ($t > 0) { $speed = $distToLast / $t; - $speed = $speed / 1000; - $speed = $speed * 3600; + $speed /= 1000; + $speed *= 3600; } if ($speed <= $STOPPED_SPEED_THRESHOLD) { @@ -757,6 +787,7 @@ public function generateTrackMetadata($file) { $moving_distance += $distToLast; } } + if ($lastPoint !== null) { $total_distance += $distToLast; } @@ -765,21 +796,21 @@ public function generateTrackMetadata($file) { $pointIndex += 1; } - if ($lastTime !== null and ($date_end === null or $lastTime > $date_end)) { + if ($lastTime instanceof \DateTime && (!$date_end instanceof \DateTime || $lastTime > $date_end)) { $date_end = $lastTime; } } # TOTAL STATS : duration, avg speed, avg_moving_speed - if ($date_end !== null and $date_begin !== null) { + if ($date_end instanceof \DateTime && $date_begin instanceof \DateTime) { $totsec = abs($date_end->getTimestamp() - $date_begin->getTimestamp()); $total_duration = $totsec; if ($totsec === 0) { $avg_speed = 0; } else { $avg_speed = $total_distance / $totsec; - $avg_speed = $avg_speed / 1000; - $avg_speed = $avg_speed * 3600; + $avg_speed /= 1000; + $avg_speed *= 3600; $avg_speed = sprintf('%.2f', $avg_speed); } } @@ -789,13 +820,13 @@ public function generateTrackMetadata($file) { $moving_pace = 0; if ($moving_time > 0) { $moving_avg_speed = $total_distance / $moving_time; - $moving_avg_speed = $moving_avg_speed / 1000; - $moving_avg_speed = $moving_avg_speed * 3600; + $moving_avg_speed /= 1000; + $moving_avg_speed *= 3600; $moving_avg_speed = sprintf('%.2f', $moving_avg_speed); // pace in minutes/km $moving_pace = $moving_time / $total_distance; - $moving_pace = $moving_pace / 60; - $moving_pace = $moving_pace * 1000; + $moving_pace /= 60; + $moving_pace *= 1000; $moving_pace = sprintf('%.2f', $moving_pace); } @@ -804,21 +835,24 @@ public function generateTrackMetadata($file) { $waypointlat = floatval($waypoint['lat']); $waypointlon = floatval($waypoint['lon']); - if ($lat === '0' and $lon === '0') { + if ($lat === '0' && $lon === '0') { $lat = $waypointlat; $lon = $waypointlon; } - if ($north === null or $waypointlat > $north) { + if ($north === null || $waypointlat > $north) { $north = $waypointlat; } - if ($south === null or $waypointlat < $south) { + + if ($south === null || $waypointlat < $south) { $south = $waypointlat; } - if ($east === null or $waypointlon > $east) { + + if ($east === null || $waypointlon > $east) { $east = $waypointlon; } - if ($west === null or $waypointlon < $west) { + + if ($west === null || $waypointlon < $west) { $west = $waypointlon; } } @@ -827,12 +861,15 @@ public function generateTrackMetadata($file) { if ($north === null) { $north = 0; } + if ($south === null) { $south = 0; } + if ($east === null) { $east = 0; } + if ($west === null) { $west = 0; } @@ -842,6 +879,7 @@ public function generateTrackMetadata($file) { foreach ($pointsBySegment as $points) { $distFilteredPointsBySegment[] = $this->getDistanceFilteredPoints($points); } + // and we get points with elevation and time for each segment $pointsWithElevationBySegment = []; $pointsWithTimeBySegment = []; @@ -852,13 +890,16 @@ public function generateTrackMetadata($file) { if (!empty($point->ele)) { $pointsWithElevationOneSegment[] = $point; } + if (!empty($point->time)) { $pointsWithTimeOneSegment[] = $point; } } + $pointsWithElevationBySegment[] = $pointsWithElevationOneSegment; $pointsWithTimeBySegment[] = $pointsWithTimeOneSegment; } + // process elevation gain/loss $pos_elevation = 0; $neg_elevation = 0; @@ -867,6 +908,7 @@ public function generateTrackMetadata($file) { $pos_elevation += $gainLoss[0]; $neg_elevation += $gainLoss[1]; } + $pos_elevation = number_format($pos_elevation, 2, '.', ''); $neg_elevation = number_format($neg_elevation, 2, '.', ''); // process max speed from distance filtered points @@ -878,18 +920,18 @@ public function generateTrackMetadata($file) { } } - $result = sprintf('{"lat":%s, "lng":%s, "name": "%s", "distance": %.3f, "duration": %d, "begin": %d, "end": %d, "posel": %.2f, "negel": %.2f, "minel": %.2f, "maxel": %.2f, "maxspd": %.2f, "avgspd": %.2f, "movtime": %d, "stptime": %d, "movavgspd": %s, "n": %.8f, "s": %.8f, "e": %.8f, "w": %.8f, "trnl": %s, "lnkurl": "%s", "lnktxt": "%s", "movpace": %.2f}', + return sprintf('{"lat":%s, "lng":%s, "name": "%s", "distance": %.3f, "duration": %d, "begin": %d, "end": %d, "posel": %.2f, "negel": %.2f, "minel": %.2f, "maxel": %.2f, "maxspd": %.2f, "avgspd": %.2f, "movtime": %d, "stptime": %d, "movavgspd": %s, "n": %.8f, "s": %.8f, "e": %.8f, "w": %.8f, "trnl": %s, "lnkurl": "%s", "lnktxt": "%s", "movpace": %.2f}', $lat, $lon, str_replace('"', "'", $name), $total_distance, $total_duration, - ($date_begin !== null) ? $date_begin->getTimestamp() : -1, - ($date_end !== null) ? $date_end->getTimestamp() : -1, + ($date_begin instanceof \DateTime) ? $date_begin->getTimestamp() : -1, + ($date_end instanceof \DateTime) ? $date_end->getTimestamp() : -1, $pos_elevation, $neg_elevation, - ($min_elevation !== null) ? $min_elevation : -1000, - ($max_elevation !== null) ? $max_elevation : -1000, + $min_elevation ?? -1000, + $max_elevation ?? -1000, $maxSpeed, $avg_speed, $moving_time, @@ -900,23 +942,25 @@ public function generateTrackMetadata($file) { $east, $west, (strlen($trackNameList) < 200) ? $trackNameList : '[]', - str_replace('"', "'", $linkurl), - str_replace('"', "'", $linktext), + str_replace('"', "'", (string)$linkurl), + str_replace('"', "'", (string)$linktext), $moving_pace ); - return $result; } - private function getDistanceFilteredPoints($points) { + /** + * @return mixed[] + */ + private function getDistanceFilteredPoints($points): array { $DISTANCE_THRESHOLD = 10; $distFilteredPoints = []; if (count($points) > 0) { - array_push($distFilteredPoints, $points[0]); + $distFilteredPoints[] = $points[0]; $lastPoint = $points[0]; foreach ($points as $point) { if (distance($lastPoint, $point) >= $DISTANCE_THRESHOLD) { - array_push($distFilteredPoints, $point); + $distFilteredPoints[] = $point; $lastPoint = $point; } } @@ -925,24 +969,28 @@ private function getDistanceFilteredPoints($points) { return $distFilteredPoints; } - private function getMaxSpeed($points) { + /** + * @param object[] $points + */ + private function getMaxSpeed(array $points): float|int { $maxSpeed = 0; - if (count($points) > 0) { + if ($points !== []) { $lastPoint = $points[0]; - $lastTime = new \DateTime($lastPoint->time); + $lastTime = new \DateTime((string)$lastPoint->time); foreach ($points as $point) { - $time = new \DateTime($point->time); + $time = new \DateTime((string)$point->time); $timeDelta = abs($lastTime->getTimestamp() - $time->getTimestamp()); if ($timeDelta > 0) { - $distance = distance($point, $lastPoint); + $distance = distance((array)$point, (array)$lastPoint); $speed = $distance / $timeDelta; - $speed = $speed / 1000; - $speed = $speed * 3600; + $speed /= 1000; + $speed *= 3600; if ($speed > $maxSpeed) { $maxSpeed = $speed; } } + $lastTime = $time; $lastPoint = $point; } @@ -953,14 +1001,16 @@ private function getMaxSpeed($points) { /** * inspired by https://www.gpsvisualizer.com/tutorials/elevation_gain.html + * @param object[] $points + * @return array */ - private function getElevationGainLoss($points) { + private function getElevationGainLoss(array $points): array { $ELEVATION_THRESHOLD = 6; $gain = 0; $loss = 0; // then calculate elevation gain with elevation threshold - if (count($points) > 0) { + if ($points !== []) { $validPoint = $points[0]; foreach ($points as $point) { $deniv = floatval($point->ele) - floatval($validPoint->ele); @@ -981,20 +1031,24 @@ private function getElevationGainLoss($points) { /* * return distance between these two gpx points in meters */ -function distance($p1, $p2) { +/** + * @param array $p1 + * @param array $p2 + */ +function distance(array $p1, array $p2): int|float { $lat1 = (float)$p1['lat']; $long1 = (float)$p1['lon']; $lat2 = (float)$p2['lat']; $long2 = (float)$p2['lon']; - if ($lat1 === $lat2 and $long1 === $long2) { + if ($lat1 === $lat2 && $long1 === $long2) { return 0; } // Convert latitude and longitude to // spherical coordinates in radians. - $degrees_to_radians = pi() / 180.0; + $degrees_to_radians = M_PI / 180.0; // phi = 90 - latitude $phi1 = (90.0 - $lat1) * $degrees_to_radians; @@ -1018,6 +1072,7 @@ function distance($p1, $p2) { if ($cos > 1.0) { $cos = 1.0; } + $arc = acos($cos); // Remember to multiply arc by the radius of the earth diff --git a/lib/Settings/AdminSettings.php b/lib/Settings/AdminSettings.php index 6793e71d0..4a6f11cfb 100644 --- a/lib/Settings/AdminSettings.php +++ b/lib/Settings/AdminSettings.php @@ -1,24 +1,23 @@ config->getAppValue('maps', $k); + $v = $this->appConfig->getValueString('maps', $k); $parameters[$k] = $v; } return new TemplateResponse('maps', 'adminSettings', $parameters, ''); } - /** - * @return string the section ID, e.g. 'sharing' - */ - public function getSection() { + #[Override] + public function getSection(): string { return 'additional'; } - /** - * @return int whether the form should be rather on the top or bottom of - * the admin section. The forms are arranged in ascending order of the - * priority values. It is required to return a value between 0 and 100. - * - * E.g.: 70 - */ - public function getPriority() { + #[Override] + public function getPriority(): int { return 5; } diff --git a/psalm.xml b/psalm.xml index 75bac237b..1cf47e261 100644 --- a/psalm.xml +++ b/psalm.xml @@ -33,6 +33,8 @@ + + diff --git a/rector.php b/rector.php new file mode 100644 index 000000000..f3f6c10b9 --- /dev/null +++ b/rector.php @@ -0,0 +1,52 @@ +withPaths([ + __DIR__ . '/lib', + __DIR__ . '/tests', + ]) + ->withSkip([ + __DIR__ . '/tests/stub.php', + __DIR__ . '/tests/stubs', + ]) + ->withImportNames( + importShortClasses: false, + ) + ->withPreparedSets( + deadCode: true, + codeQuality: true, + codingStyle: true, + typeDeclarations: true, + typeDeclarationDocblocks: true, + privatization: true, + instanceOf: true, + earlyReturn: true, + rectorPreset: true, + phpunitCodeQuality: true, + doctrineCodeQuality: true, + symfonyCodeQuality: true, + symfonyConfigs: true, + )->withPhpSets( + php81: true, + )->withConfiguredRule(ClassPropertyAssignToConstructorPromotionRector::class, [ + 'inline_public' => true, + 'rename_property' => true, + ]) + ->withSets([ + NextcloudSets::NEXTCLOUD_30, + PHPUnitSetList::PHPUNIT_100, + ]) + ->withRules([ + SafeDeclareStrictTypesRector::class, + ]); diff --git a/tests/Integration/AppTest.php b/tests/Integration/AppTest.php index a5d9d061c..753834fc3 100644 --- a/tests/Integration/AppTest.php +++ b/tests/Integration/AppTest.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Tests\Integration\Controller; +use OCP\App\IAppManager; use OCP\AppFramework\App; +use PHPUnit\Framework\TestCase; /** * This test shows how to make a small Integration Test. Query your class * directly from the container, only pass in mocks if needed and run your tests * against the database */ -class AppTest extends \PHPUnit\Framework\TestCase { +final class AppTest extends TestCase { private $container; @@ -28,8 +31,8 @@ protected function setUp(): void { $this->container = $app->getContainer(); } - public function testAppInstalled() { - $appManager = $this->container->query(\OCP\App\IAppManager::class); + public function testAppInstalled(): void { + $appManager = $this->container->query(IAppManager::class); $this->assertTrue($appManager->isInstalled('maps')); } } diff --git a/tests/Integration/Db/FavoriteShareMapperTest.php b/tests/Integration/Db/FavoriteShareMapperTest.php index 95e75ddff..f7f103211 100644 --- a/tests/Integration/Db/FavoriteShareMapperTest.php +++ b/tests/Integration/Db/FavoriteShareMapperTest.php @@ -1,5 +1,7 @@ * @@ -21,33 +23,35 @@ * along with this program. If not, see . * */ - namespace tests\Integration\Db; use ChristophWurst\Nextcloud\Testing\DatabaseTransaction; use ChristophWurst\Nextcloud\Testing\TestCase; -use OC; use OCA\Maps\DB\FavoriteShare; use OCA\Maps\DB\FavoriteShareMapper; use OCP\AppFramework\Db\DoesNotExistException; +use OCP\Files\IRootFolder; +use OCP\IDBConnection; +use OCP\Security\ISecureRandom; +use OCP\Server; -class FavoriteShareMapperTest extends TestCase { +final class FavoriteShareMapperTest extends TestCase { use DatabaseTransaction; /* @var FavoriteShareMapper */ - private $mapper; + private FavoriteShareMapper $mapper; - public function setUp(): void { + protected function setUp(): void { parent::setUp(); $this->mapper = new FavoriteShareMapper( - OC::$server->query(\OCP\IDBConnection::class), - OC::$server->getSecureRandom(), - OC::$server->getRootFolder() + Server::get(IDBConnection::class), + Server::get(ISecureRandom::class), + Server::get(IRootFolder::class) ); } - public function testCreateByOwnerAndTokenIsSuccessful() { + public function testCreateByOwnerAndTokenIsSuccessful(): void { /* @var FavoriteShare */ $share = $this->mapper->create('testUser', 'testCategory'); @@ -56,7 +60,7 @@ public function testCreateByOwnerAndTokenIsSuccessful() { $this->assertEquals('testCategory', $share->getCategory()); } - public function testFindByTokenIsSuccessful() { + public function testFindByTokenIsSuccessful(): void { /* @var FavoriteShare */ $shareExpected = $this->mapper->create('testUser', 'testCategory'); @@ -68,7 +72,7 @@ public function testFindByTokenIsSuccessful() { $this->assertEquals($shareExpected->getCategory(), $shareActual->getCategory()); } - public function testFindByOwnerAndCategoryIsSuccessful() { + public function testFindByOwnerAndCategoryIsSuccessful(): void { /* @var FavoriteShare */ $shareExpected = $this->mapper->create('testUser', 'testCategory'); @@ -80,7 +84,7 @@ public function testFindByOwnerAndCategoryIsSuccessful() { $this->assertEquals($shareExpected->getCategory(), $shareActual->getCategory()); } - public function testFindAllByOwnerIsSuccessfulAndDoesNotContainOtherShares() { + public function testFindAllByOwnerIsSuccessfulAndDoesNotContainOtherShares(): void { /* @var FavoriteShare */ $share1 = $this->mapper->create('testUser', 'testCategory1'); @@ -92,25 +96,24 @@ public function testFindAllByOwnerIsSuccessfulAndDoesNotContainOtherShares() { /* @var array */ $shares = $this->mapper->findAllByOwner('testUser'); - $shareTokens = array_map(function ($share) { - return $share->getToken(); - }, $shares); + $shareTokens = array_map(fn (FavoriteShare $share) => $share->getToken(), $shares); - $this->assertEquals(2, count($shareTokens)); + $this->assertCount(2, $shareTokens); $this->assertContains($share1->getToken(), $shareTokens); $this->assertContains($share2->getToken(), $shareTokens); } - public function testFindOrCreateByOwnerAndCategoryIsSuccessful() { + public function testFindOrCreateByOwnerAndCategoryIsSuccessful(): void { /* @var FavoriteShare */ $share = $this->mapper->findOrCreateByOwnerAndCategory('testUser', 'testCategory'); + $this->assertInstanceOf(FavoriteShare::class, $share); $this->assertIsString($share->getToken()); $this->assertEquals('testUser', $share->getOwner()); $this->assertEquals('testCategory', $share->getCategory()); } - public function testRemoveByOwnerAndCategoryIsSuccessful() { + public function testRemoveByOwnerAndCategoryIsSuccessful(): void { /* @var FavoriteShare */ $share = $this->mapper->create('testUser', 'testCategory'); diff --git a/tests/Unit/Controller/ContactsControllerTest.php b/tests/Unit/Controller/ContactsControllerTest.php index 580a72861..ad1c0ac26 100644 --- a/tests/Unit/Controller/ContactsControllerTest.php +++ b/tests/Unit/Controller/ContactsControllerTest.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; use OCA\DAV\CardDAV\CardDavBackend; - use OCA\DAV\CardDAV\ContactsManager; use OCA\Maps\AppInfo\Application; use OCA\Maps\Service\AddressService; + use OCP\BackgroundJob\IJobList; use OCP\Contacts\IManager as IContactManager; use OCP\Files\IAppData; use OCP\Files\IRootFolder; +use OCP\IAvatarManager; use OCP\ICacheFactory; +use OCP\IDBConnection; use OCP\IGroupManager; use OCP\IURLGenerator; use OCP\IUserManager; -use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; -class ContactsControllerTest extends \PHPUnit\Framework\TestCase { - private $appName; - private $request; +final class ContactsControllerTest extends TestCase { + + private $mapFolder; - private $container; - private $app; - private IAppData&MockObject $appData; - private $contactsController; - private $cdBackend; + + private ContactsController $contactsController; + + private $root; public static function setUpBeforeClass(): void { @@ -56,16 +58,20 @@ public static function setUpBeforeClass(): void { $user = $c->get(IUserManager::class)->createUser('test', 'tatotitoTUTU'); $user->setEMailAddress('toto@toto.net'); } + if ($user2 === null) { $user2 = $c->get(IUserManager::class)->createUser('test2', 'plopinoulala000'); } + if ($user3 === null) { $user3 = $c->get(IUserManager::class)->createUser('test3', 'yeyeahPASSPASS'); } + if ($group === null) { $c->get(IGroupManager::class)->createGroup('group1test'); $c->get(IGroupManager::class)->get('group1test')->addUser($user); } + if ($group2 === null) { $c->get(IGroupManager::class)->createGroup('group2test'); $c->get(IGroupManager::class)->get('group2test')->addUser($user2); @@ -73,50 +79,46 @@ public static function setUpBeforeClass(): void { } protected function setUp(): void { - $this->app = new Application(); - $c = $this->app->getContainer(); + $app = new Application(); + $c = $app->getContainer(); - $this->appName = 'maps'; - $this->request = $this->getMockBuilder('\OCP\IRequest') - ->disableOriginalConstructor() - ->getMock(); + $appName = 'maps'; + $request = $this->createMock('\OCP\IRequest'); $urlGenerator = $c->get(IURlGenerator::class); - $this->contactsManager = $c->get(IContactManager::class); - $this->cm = $c->get(ContactsManager::class); - $this->cm->setupContactsProvider($this->contactsManager, 'test', $urlGenerator); + $contactsManager = $c->get(IContactManager::class); + $cm = $c->get(ContactsManager::class); + $cm->setupContactsProvider($contactsManager, 'test', $urlGenerator); - $this->app = new Application(); - $this->container = $this->app->getContainer(); - $c = $this->container; + $app = new Application(); + $container = $app->getContainer(); + $c = $container; - $this->appData = $this->createMock(\OCP\Files\IAppData::class); + $appData = $this->createMock(IAppData::class); - $this->addressService = new AddressService( + $addressService = new AddressService( $c->get(ICacheFactory::class), $c->get(LoggerInterface::class), $c->get(IJobList::class), - $this->appData, - $c->get(\OCP\IDBConnection::class) + $appData, + $c->get(IDBConnection::class) ); - $this->userPrincipalBackend = $this->createMock(\OCA\DAV\Connector\Sabre\Principal::class); - - $this->cdBackend = $c->get(CardDavBackend::class); + $cdBackend = $c->get(CardDavBackend::class); $this->root = $c->get(IRootFolder::class); $this->mapFolder = $this->createMapFolder(); $this->contactsController = new ContactsController( - $this->appName, - $this->request, - $c->get(\OCP\IDBConnection::class), - $this->contactsManager, - $this->addressService, + $appName, + $request, + $c->get(IDBConnection::class), + $contactsManager, + $addressService, 'test', - $this->cdBackend, - $c->get(\OCP\IAvatarManager::class), + $cdBackend, + $c->get(IAvatarManager::class), $this->root, $urlGenerator); } @@ -125,9 +127,9 @@ private function createMapFolder() { $userFolder = $this->root->getUserFolder('test'); if ($userFolder->nodeExists('Map')) { return $userFolder->get('Map'); - } else { - return $userFolder->newFolder('Map'); } + + return $userFolder->newFolder('Map'); } public static function tearDownAfterClass(): void { @@ -137,8 +139,7 @@ protected function tearDown(): void { // in case there was a failure and something was not deleted } - public function testAddContact() { - $c = $this->container; + public function testAddContact(): void { //$this->contacts->createOrUpdate() //var_dump($this->contactsManager->isEnabled()); // TODO understand why this only returns system address book @@ -147,12 +148,11 @@ public function testAddContact() { $resp = $this->contactsController->getContacts(); $status = $resp->getStatus(); $this->assertEquals(200, $status); - $data = $resp->getData(); + $resp->getData(); //var_dump($data); } - public function testAddContactMyMap() { - $c = $this->container; + public function testAddContactMyMap(): void { //$this->contacts->createOrUpdate() //var_dump($this->contactsManager->isEnabled()); // TODO understand why this only returns system address book @@ -161,7 +161,7 @@ public function testAddContactMyMap() { $resp = $this->contactsController->getContacts($this->mapFolder->getId()); $status = $resp->getStatus(); $this->assertEquals(200, $status); - $data = $resp->getData(); + $resp->getData(); //var_dump($data); } diff --git a/tests/Unit/Controller/DevicesApiControllerTest.php b/tests/Unit/Controller/DevicesApiControllerTest.php index 5498c6bb9..0d86b2763 100644 --- a/tests/Unit/Controller/DevicesApiControllerTest.php +++ b/tests/Unit/Controller/DevicesApiControllerTest.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; use OCA\Maps\AppInfo\Application; use OCA\Maps\Service\DevicesService; +use OCP\IGroupManager; use OCP\IServerContainer; +use OCP\IUserManager; +use OCP\L10N\IFactory; +use PHPUnit\Framework\TestCase; -class DevicesApiControllerTest extends \PHPUnit\Framework\TestCase { - private $appName; - private $request; - private $contacts; +final class DevicesApiControllerTest extends TestCase { - private $container; - private $config; - private $app; - - private $devicesApiController; - private $devicesApiController2; - private $root; + private DevicesApiController $devicesApiController; public static function setUpBeforeClass(): void { $app = new Application(); $c = $app->getContainer(); - $user = $c->getServer()->getUserManager()->get('test'); - $user2 = $c->getServer()->getUserManager()->get('test2'); - $user3 = $c->getServer()->getUserManager()->get('test3'); - $group = $c->getServer()->getGroupManager()->get('group1test'); - $group2 = $c->getServer()->getGroupManager()->get('group2test'); + $user = $c->get(IUserManager::class)->get('test'); + $user2 = $c->get(IUserManager::class)->get('test2'); + $user3 = $c->get(IUserManager::class)->get('test3'); + $group = $c->get(IGroupManager::class)->get('group1test'); + $group2 = $c->get(IGroupManager::class)->get('group2test'); // CREATE DUMMY USERS if ($user === null) { - $u1 = $c->getServer()->getUserManager()->createUser('test', 'tatotitoTUTU'); + $u1 = $c->get(IUserManager::class)->createUser('test', 'tatotitoTUTU'); $u1->setEMailAddress('toto@toto.net'); } + if ($user2 === null) { - $u2 = $c->getServer()->getUserManager()->createUser('test2', 'plopinoulala000'); + $user3 = $c->get(IUserManager::class)->createUser('test2', 'plopinoulala000'); } - if ($user2 === null) { - $u3 = $c->getServer()->getUserManager()->createUser('test3', 'yeyeahPASSPASS'); + + if ($user3 === null) { + $user3 = $c->get(IUserManager::class)->createUser('test3', 'yeyeahPASSPASS'); } + if ($group === null) { - $c->getServer()->getGroupManager()->createGroup('group1test'); - $u1 = $c->getServer()->getUserManager()->get('test'); - $c->getServer()->getGroupManager()->get('group1test')->addUser($u1); + $c->get(IGroupManager::class)->createGroup('group1test'); + $c->get(IGroupManager::class)->get('group1test')->addUser($user1); } + if ($group2 === null) { - $c->getServer()->getGroupManager()->createGroup('group2test'); - $u2 = $c->getServer()->getUserManager()->get('test2'); - $c->getServer()->getGroupManager()->get('group2test')->addUser($u2); + $c->get(IGroupManager::class)->createGroup('group2test'); + $c->get(IGroupManager::class)->get('group2test')->addUser($user2); } } protected function setUp(): void { - $this->appName = 'maps'; - $this->request = $this->getMockBuilder('\OCP\IRequest') - ->disableOriginalConstructor() - ->getMock(); - $this->contacts = $this->getMockBuilder('OCP\Contacts\IManager') - ->disableOriginalConstructor() - ->getMock(); - - $this->app = new Application(); - $this->container = $this->app->getContainer(); - $c = $this->container; - $this->config = $c->query(IServerContainer::class)->getConfig(); - $this->root = $c->query(IServerContainer::class)->getRootFolder(); + $appName = 'maps'; + $request = $this->createMock('\OCP\IRequest'); + + $app = new Application(); + $container = $app->getContainer(); + $c = $container; $this->devicesApiController = new DevicesApiController( - $this->appName, - $this->request, - $c->query(IServerContainer::class), - $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->get(\OCP\Share\IManager::class), - $c->getServer()->getAppManager(), - $c->getServer()->getUserManager(), - $c->getServer()->getGroupManager(), - $c->query(IServerContainer::class)->getL10N($c->query('AppName')), - $c->query(DevicesService::class), + $appName, + $request, + $c->get(IFactory::class)->get('maps'), + $c->get(DevicesService::class), 'test' ); - $this->devicesApiController2 = new DevicesApiController( - $this->appName, - $this->request, - $c->query(IServerContainer::class), - $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->get(\OCP\Share\IManager::class), - $c->getServer()->getAppManager(), - $c->getServer()->getUserManager(), - $c->getServer()->getGroupManager(), - $c->query(IServerContainer::class)->getL10N($c->query('AppName')), - $c->query(DevicesService::class), - 'test2' - ); - // delete $resp = $this->devicesApiController->getDevices('1.0'); $data = $resp->getData(); @@ -120,7 +91,7 @@ protected function tearDown(): void { // in case there was a failure and something was not deleted } - public function testAddPoints() { + public function testAddPoints(): void { $resp = $this->devicesApiController->getDevices('1.0'); $data = $resp->getData(); foreach ($data as $device) { @@ -139,8 +110,6 @@ public function testAddPoints() { $status = $resp->getStatus(); $this->assertEquals(200, $status); $data = $resp->getData(); - $deviceId = $data['deviceId']; - $pointId = $data['pointId']; $_SERVER['HTTP_USER_AGENT'] = 'testBrowser'; $ts = (new \DateTime())->getTimestamp(); @@ -149,7 +118,6 @@ public function testAddPoints() { $this->assertEquals(200, $status); $data = $resp->getData(); $deviceId2 = $data['deviceId']; - $pointId2 = $data['pointId']; // test user agent is correct $resp = $this->devicesApiController->getDevices('1.0'); $data = $resp->getData(); @@ -160,6 +128,7 @@ public function testAddPoints() { $d2Found = true; } } + $this->assertEquals(true, $d2Found); // This happens with a request such as /api/1.0/devices?lat=1.1&lng=2.2×tamp=&user_agent=testDevice&altitude=&battery=&accuracy= @@ -167,8 +136,6 @@ public function testAddPoints() { $status = $resp->getStatus(); $this->assertEquals(200, $status); $data = $resp->getData(); - $deviceId3 = $data['deviceId']; - $pointId3 = $data['pointId']; // test point values $resp = $this->devicesApiController->getDevicePoints($deviceId2); @@ -192,7 +159,7 @@ public function testAddPoints() { $this->assertEquals('Invalid values', $data); } - public function testEditDevice() { + public function testEditDevice(): void { $resp = $this->devicesApiController->getDevices('1.0'); $data = $resp->getData(); foreach ($data as $device) { @@ -204,7 +171,6 @@ public function testEditDevice() { $this->assertEquals(200, $status); $data = $resp->getData(); $deviceId = $data['deviceId']; - $pointId = $data['pointId']; $resp = $this->devicesApiController->editDevice($deviceId, '#001122'); $status = $resp->getStatus(); @@ -228,7 +194,7 @@ public function testEditDevice() { // $resp = $this->devicesApiController->deleteDevice($device['id']); // } - // $userfolder = $this->container->query(IServerContainer::class)->getUserFolder('test'); + // $userfolder = $this->container->get(IServerContainer::class)->getUserFolder('test'); // $content1 = file_get_contents('tests/test_files/devicesOk.gpx'); // $userfolder->newFile('devicesOk.gpx')->putContent($content1); @@ -325,8 +291,8 @@ public function testEditDevice() { // $this->assertEquals('Nothing to export', $data); //} - public function testEditDevices() { - $this->assertEquals(true, 1 == 1); + public function testEditDevices(): void { + $this->assertEquals(true, 1 === 1); //// valid edition //$resp = $this->favoritesController->addFavorite('a', 3.1, 4.1, 'cat1', null, null); //$favId = $resp->getData()['id']; diff --git a/tests/Unit/Controller/DevicesControllerTest.php b/tests/Unit/Controller/DevicesControllerTest.php index 357f35993..918530b7b 100644 --- a/tests/Unit/Controller/DevicesControllerTest.php +++ b/tests/Unit/Controller/DevicesControllerTest.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; use OCA\Maps\AppInfo\Application; use OCA\Maps\DB\DeviceShareMapper; use OCA\Maps\Service\DevicesService; use OCP\Files\IRootFolder; -use OCP\IConfig; +use OCP\IAppConfig; +use OCP\IDateTimeZone; use OCP\IGroupManager; use OCP\IRequest; -use OCP\IServerContainer; use OCP\IUserManager; use OCP\L10N\IFactory; -use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; -class DevicesControllerTest extends \PHPUnit\Framework\TestCase { - private string $appName; - private IRequest&MockObject $request; +final class DevicesControllerTest extends TestCase { private ContainerInterface $container; - private Application $app; private DevicesController $devicesController; @@ -48,17 +46,21 @@ public static function setUpBeforeClass(): void { $u1 = $c->get(IUserManager::class)->createUser('test', 'tatotitoTUTU'); $u1->setEMailAddress('toto@toto.net'); } + if ($user2 === null) { $u2 = $c->get(IUserManager::class)->createUser('test2', 'plopinoulala000'); } + if ($user3 === null) { $u3 = $c->get(IUserManager::class)->createUser('test3', 'yeyeahPASSPASS'); } + if ($group === null) { $c->get(IGroupManager::class)->createGroup('group1test'); $u1 = $c->get(IGroupManager::class)->get('test'); $c->get(IGroupManager::class)->get('group1test')->addUser($u1); } + if ($group2 === null) { $c->get(IGroupManager::class)->createGroup('group2test'); $u2 = $c->get(IGroupManager::class)->get('test2'); @@ -67,23 +69,21 @@ public static function setUpBeforeClass(): void { } protected function setUp(): void { - $this->appName = 'maps'; - $this->request = $this->createMock(\OCP\IRequest::class); + $appName = 'maps'; + $request = $this->createMock(IRequest::class); - $this->app = new Application(); - $this->container = $this->app->getContainer(); + $app = new Application(); + $this->container = $app->getContainer(); $c = $this->container; - $this->config = $c->get(IConfig::class); - $this->root = $c->get(IRootFolder::class); $this->devicesController = new DevicesController( - $this->appName, - $this->request, - $c->get(IConfig::class), + $appName, + $request, + $c->get(IAppConfig::class), $c->get(IFactory::class)->get('maps'), $c->get(DevicesService::class), $c->get(DeviceShareMapper::class), - $c->get(\OCP\IDateTimeZone::class), + $c->get(IDateTimeZone::class), $c->get(IRootFolder::class), 'test' ); @@ -92,7 +92,7 @@ protected function setUp(): void { $resp = $this->devicesController->getDevices(); $data = $resp->getData(); foreach ($data as $device) { - $resp = $this->devicesController->deleteDevice($device['id']); + $this->devicesController->deleteDevice($device['id']); } } @@ -113,7 +113,7 @@ protected function tearDown(): void { // in case there was a failure and something was not deleted } - public function testAddPoints() { + public function testAddPoints(): void { $resp = $this->devicesController->getDevices(); $data = $resp->getData(); foreach ($data as $device) { @@ -133,7 +133,6 @@ public function testAddPoints() { $this->assertEquals(200, $status); $data = $resp->getData(); $deviceId = $data['deviceId']; - $pointId = $data['pointId']; $_SERVER['HTTP_USER_AGENT'] = 'testBrowser'; $ts = (new \DateTime())->getTimestamp(); @@ -142,7 +141,6 @@ public function testAddPoints() { $this->assertEquals(200, $status); $data = $resp->getData(); $deviceId2 = $data['deviceId']; - $pointId2 = $data['pointId']; // test user agent is correct $resp = $this->devicesController->getDevices(); $data = $resp->getData(); @@ -153,6 +151,7 @@ public function testAddPoints() { $d2Found = true; } } + $this->assertEquals(true, $d2Found); // test point values @@ -164,7 +163,7 @@ public function testAddPoints() { $this->assertEquals(true, $data[0]['timestamp'] >= $ts); // test missing values - $resp = $this->devicesController->addDevicePoint(1.1, 2.2, 12346, 'testDevice', null, null, null); + $resp = $this->devicesController->addDevicePoint(1.1, 2.2, 12346, 'testDevice'); $status = $resp->getStatus(); $this->assertEquals(200, $status); @@ -196,7 +195,7 @@ public function testAddPoints() { $this->assertEquals('Invalid values', $data); } - public function testEditDevice() { + public function testEditDevice(): void { $resp = $this->devicesController->getDevices(); $data = $resp->getData(); foreach ($data as $device) { @@ -208,7 +207,6 @@ public function testEditDevice() { $this->assertEquals(200, $status); $data = $resp->getData(); $deviceId = $data['deviceId']; - $pointId = $data['pointId']; $resp = $this->devicesController->editDevice($deviceId, '#001122', 'editedDevice'); $status = $resp->getStatus(); @@ -226,14 +224,14 @@ public function testEditDevice() { $this->assertEquals(400, $status); } - public function testImportExportDevices() { + public function testImportExportDevices(): void { $resp = $this->devicesController->getDevices(); $data = $resp->getData(); foreach ($data as $device) { $resp = $this->devicesController->deleteDevice($device['id']); } - $userfolder = $this->container->query(IServerContainer::class)->getUserFolder('test'); + $userfolder = $this->container->get(IRootFolder::class)->getUserFolder('test'); $content1 = file_get_contents('tests/test_files/devicesOk.gpx'); $userfolder->newFile('devicesOk.gpx')->putContent($content1); @@ -265,6 +263,7 @@ public function testImportExportDevices() { $id = $device['id']; $devices[$id] = $device; } + // get number of points foreach ($devices as $id => $device) { $resp = $this->devicesController->getDevicePoints($id); @@ -284,18 +283,19 @@ public function testImportExportDevices() { // parse xml and compare number of devices and points $xmLData = $userfolder->get($exportPath)->getContent(); - $xml = simplexml_load_string($xmLData); + $xml = simplexml_load_string((string)$xmLData); $trks = $xml->trk; // number of devices - $this->assertEquals(count($ids), count($trks)); + $this->assertCount(count($ids), $trks); $pointCountExport = []; // count exported points per device foreach ($trks as $trk) { $name = (string)$trk->name[0]; $pointCountExport[$name] = count($trk->trkseg[0]->trkpt); } + // check that it matches the data in the DB - foreach ($devices as $id => $device) { + foreach ($devices as $device) { $this->assertEquals($device['nbPoints'], $pointCountExport[$device['user_agent']]); } @@ -330,8 +330,8 @@ public function testImportExportDevices() { $this->assertEquals('Nothing to export', $data); } - public function testEditDevices() { - $this->assertEquals(true, 1 == 1); + public function testEditDevices(): void { + $this->assertEquals(true, 1 === 1); //// valid edition //$resp = $this->favoritesController->addFavorite('a', 3.1, 4.1, 'cat1', null, null); //$favId = $resp->getData()['id']; diff --git a/tests/Unit/Controller/FavoritesApiControllerTest.php b/tests/Unit/Controller/FavoritesApiControllerTest.php index d35c8d38f..0c470c1f2 100644 --- a/tests/Unit/Controller/FavoritesApiControllerTest.php +++ b/tests/Unit/Controller/FavoritesApiControllerTest.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; use OCA\Maps\AppInfo\Application; use OCA\Maps\Service\FavoritesService; -use OCP\IServerContainer; +use OCP\IGroupManager; +use OCP\IUserManager; +use OCP\L10N\IFactory; +use PHPUnit\Framework\TestCase; -class FavoritesApiControllerTest extends \PHPUnit\Framework\TestCase { - private $appName; - private $request; - private $contacts; +final class FavoritesApiControllerTest extends TestCase { - private $container; - private $config; - private $app; - private $root; - - private $favoritesApiController; - private $favoritesApiController2; + private FavoritesApiController $favoritesApiController; public static function setUpBeforeClass(): void { $app = new Application(); $c = $app->getContainer(); - $user = $c->getServer()->getUserManager()->get('test'); - $user2 = $c->getServer()->getUserManager()->get('test2'); - $user3 = $c->getServer()->getUserManager()->get('test3'); - $group = $c->getServer()->getGroupManager()->get('group1test'); - $group2 = $c->getServer()->getGroupManager()->get('group2test'); + $user = $c->get(IUserManager::class)->get('test'); + $user2 = $c->get(IUserManager::class)->get('test2'); + $c->get(IUserManager::class)->get('test3'); + $group = $c->get(IGroupManager::class)->get('group1test'); + $group2 = $c->get(IGroupManager::class)->get('group2test'); // CREATE DUMMY USERS if ($user === null) { - $u1 = $c->getServer()->getUserManager()->createUser('test', 'tatotitoTUTU'); + $u1 = $c->get(IUserManager::class)->createUser('test', 'tatotitoTUTU'); $u1->setEMailAddress('toto@toto.net'); } + if ($user2 === null) { - $u2 = $c->getServer()->getUserManager()->createUser('test2', 'plopinoulala000'); - } - if ($user2 === null) { - $u3 = $c->getServer()->getUserManager()->createUser('test3', 'yeyeahPASSPASS'); + $u2 = $c->get(IUserManager::class)->createUser('test2', 'plopinoulala000'); + $u3 = $c->get(IUserManager::class)->createUser('test3', 'yeyeahPASSPASS'); } + if ($group === null) { - $c->getServer()->getGroupManager()->createGroup('group1test'); - $u1 = $c->getServer()->getUserManager()->get('test'); - $c->getServer()->getGroupManager()->get('group1test')->addUser($u1); + $c->get(IGroupManager::class)->createGroup('group1test'); + $u1 = $c->get(IUserManager::class)->get('test'); + $c->get(IGroupManager::class)->get('group1test')->addUser($u1); } + if ($group2 === null) { - $c->getServer()->getGroupManager()->createGroup('group2test'); - $u2 = $c->getServer()->getUserManager()->get('test2'); - $c->getServer()->getGroupManager()->get('group2test')->addUser($u2); + $c->get(IGroupManager::class)->createGroup('group2test'); + $u2 = $c->get(IUserManager::class)->get('test2'); + $c->get(IGroupManager::class)->get('group2test')->addUser($u2); } } protected function setUp(): void { - $this->appName = 'maps'; - $this->request = $this->getMockBuilder('\OCP\IRequest') - ->disableOriginalConstructor() - ->getMock(); - $this->contacts = $this->getMockBuilder('OCP\Contacts\IManager') - ->disableOriginalConstructor() - ->getMock(); - - $this->app = new Application(); - $this->container = $this->app->getContainer(); - $c = $this->container; - $this->config = $c->query(IServerContainer::class)->getConfig(); - $this->root = $c->query(IServerContainer::class)->getRootFolder(); + $appName = 'maps'; + $request = $this->createMock('\OCP\IRequest'); + + $app = new Application(); + $container = $app->getContainer(); + $c = $container; $this->favoritesApiController = new FavoritesApiController( - $this->appName, - $this->request, - $c->query(IServerContainer::class), - $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->get(\OCP\Share\IManager::class), - $c->getServer()->getAppManager(), - $c->getServer()->getUserManager(), - $c->getServer()->getGroupManager(), - $c->query(IServerContainer::class)->getL10N($c->query('AppName')), - $c->query(FavoritesService::class), + $appName, + $request, + $c->get(IFactory::class)->get('maps'), + $c->get(FavoritesService::class), 'test' ); - - $this->favoritesApiController2 = new FavoritesApiController( - $this->appName, - $this->request, - $c->query(IServerContainer::class), - $c->query(IServerContainer::class)->getConfig(), - $c->getServer()->get(\OCP\Share\IManager::class), - $c->getServer()->getAppManager(), - $c->getServer()->getUserManager(), - $c->getServer()->getGroupManager(), - $c->query(IServerContainer::class)->getL10N($c->query('AppName')), - $c->query(FavoritesService::class), - 'test2' - ); } public static function tearDownAfterClass(): void { //$app = new Application(); //$c = $app->getContainer(); - //$user = $c->getServer()->getUserManager()->get('test'); + //$user = $c->get(IUserManager::class)->get('test'); //$user->delete(); - //$user = $c->getServer()->getUserManager()->get('test2'); + //$user = $c->get(IUserManager::class)->get('test2'); //$user->delete(); - //$user = $c->getServer()->getUserManager()->get('test3'); + //$user = $c->get(IUserManager::class)->get('test3'); //$user->delete(); - //$c->getServer()->getGroupManager()->get('group1test')->delete(); - //$c->getServer()->getGroupManager()->get('group2test')->delete(); + //$c->get(IGroupManager::class)->get('group1test')->delete(); + //$c->get(IGroupManager::class)->get('group2test')->delete(); } protected function tearDown(): void { @@ -128,7 +97,7 @@ protected function tearDown(): void { } } - public function testAddFavorites() { + public function testAddFavorites(): void { // correct values $resp = $this->favoritesApiController->addFavorite('1.0', 'one', 3.1, 4.2, '', null, null); $status = $resp->getStatus(); @@ -158,7 +127,7 @@ public function testAddFavorites() { $status = $resp->getStatus(); $this->assertEquals(200, $status); $data = $resp->getData(); - $this->assertEquals(2, count($data)); + $this->assertCount(2, $data); //// get favorites using etag //$etag = $resp->getEtag(); @@ -189,7 +158,7 @@ public function testAddFavorites() { $this->assertEquals(400, $status); } - public function testEditFavorites() { + public function testEditFavorites(): void { // valid edition $resp = $this->favoritesApiController->addFavorite('1.0', 'a', 3.1, 4.1, 'cat1', null, null); $favId = $resp->getData()['id']; @@ -207,13 +176,14 @@ public function testEditFavorites() { if ($fav['id'] === $favId) { $seen = true; $this->assertEquals('aa', $fav['name']); - $this->assertEquals(3.2, $fav['lat']); - $this->assertEquals(4.2, $fav['lng']); + $this->assertEqualsWithDelta(3.2, $fav['lat'], PHP_FLOAT_EPSILON); + $this->assertEqualsWithDelta(4.2, $fav['lng'], PHP_FLOAT_EPSILON); $this->assertEquals('cat2', $fav['category']); $this->assertEquals('comment', $fav['comment']); $this->assertEquals('ext', $fav['extensions']); } } + $this->assertEquals(true, $seen); // invalid edition diff --git a/tests/Unit/Controller/FavoritesControllerTest.php b/tests/Unit/Controller/FavoritesControllerTest.php index c7165f81e..42bc92b0b 100644 --- a/tests/Unit/Controller/FavoritesControllerTest.php +++ b/tests/Unit/Controller/FavoritesControllerTest.php @@ -1,5 +1,7 @@ get(IUserManager::class)->createUser('test', 'tatotitoTUTU'); $u1->setEMailAddress('toto@toto.net'); } + if ($user2 === null) { $c->get(IUserManager::class)->createUser('test2', 'plopinoulala000'); } + if ($user3 === null) { $c->get(IUserManager::class)->createUser('test3', 'yeyeahPASSPASS'); } + if ($group === null) { $c->get(IGroupManager::class)->createGroup('group1test'); - $u1 = $c->get(IGroupManager::class)->get('test'); - $c->get(IGroupManager::class)->get('group1test')->addUser($u1); + $c->get(IGroupManager::class)->get('group1test')->addUser($user1); } + if ($group2 === null) { $c->get(IGroupManager::class)->createGroup('group2test'); - $u2 = $c->get(IGroupManager::class)->get('test2'); - $c->get(IGroupManager::class)->get('group2test')->addUser($u2); + $c->get(IGroupManager::class)->get('group2test')->addUser($user2); } } protected function setUp(): void { - $this->appName = 'maps'; - $this->request = $this->createMock(IRequest::class); + $appName = 'maps'; + $request = $this->createMock(IRequest::class); - $this->app = new Application(); - $this->container = $this->app->getContainer(); + $app = new Application(); + $this->container = $app->getContainer(); $c = $this->container; - $this->config = $c->get(IConfig::class); + $this->root = $c->get(IRootFolder::class); $this->favoritesController = new FavoritesController( - $this->appName, - $this->request, - $c->get(IServerContainer::class), - $c->get(IConfig::class), - $c->get(\OCP\Share\IManager::class), - $c->get(IAppManager::class), - $c->get(IUserManager::class), - $c->get(IGroupManager::class), - $c->get(IFactory::class)->get($this->appName), + $appName, + $request, + $c->get(IAppConfig::class), + $this->root, + $c->get(IFactory::class)->get($appName), $c->get(FavoritesService::class), - $c->get(\OCP\IDateTimeZone::class), + $c->get(IDateTimeZone::class), $c->get(FavoriteShareMapper::class), 'test' ); $this->favoritesController2 = new FavoritesController( - $this->appName, - $this->request, - $c->get(IServerContainer::class), - $c->get(IConfig::class), - $c->get(\OCP\Share\IManager::class), - $c->get(IAppManager::class), - $c->get(IUserManager::class), - $c->get(IGroupManager::class), - $c->get(IFactory::class)->get($this->appName), + $appName, + $request, + $c->get(IAppConfig::class), + $this->root, + $c->get(IFactory::class)->get($appName), $c->get(FavoritesService::class), - $c->get(\OCP\IDateTimeZone::class), + $c->get(IDateTimeZone::class), $c->get(FavoriteShareMapper::class), 'test2' ); @@ -122,6 +118,7 @@ private function createMapFolder(): Folder { if ($userFolder->nodeExists('Map')) { $userFolder->get('Map')->delete(); } + return $userFolder->newFolder('Map'); } @@ -147,7 +144,7 @@ protected function tearDown(): void { } } - public function testAddFavorites() { + public function testAddFavorites(): void { // correct values $resp = $this->favoritesController->addFavorite('one', 3.1, 4.2, '', null, null); $status = $resp->getStatus(); @@ -178,7 +175,7 @@ public function testAddFavorites() { $status = $resp->getStatus(); $this->assertEquals(200, $status); $data = $resp->getData(); - $this->assertEquals(2, count($data)); + $this->assertCount(2, $data); // delete created favorites $resp = $this->favoritesController->deleteFavorite($id1); @@ -239,7 +236,7 @@ public function testAddFavoritesMyMap(): void { $status = $resp->getStatus(); $this->assertEquals(200, $status); $data = $resp->getData(); - $this->assertEquals(3, count($data)); + $this->assertCount(3, $data); // delete created favorites0 $resp = $this->favoritesController->deleteFavorite($id3, $myMapId); @@ -260,8 +257,8 @@ public function testAddFavoritesMyMap(): void { $this->assertEquals(400, $status); } - public function testImportExportFavorites() { - $userfolder = $this->container->query(IServerContainer::class)->getUserFolder('test'); + public function testImportExportFavorites(): void { + $userfolder = $this->container->get(IRootFolder::class)->getUserFolder('test'); $content1 = file_get_contents('tests/test_files/favoritesOk.gpx'); $newFile = $userfolder->newFile('favoritesOk.gpx'); $newFile->putContent($content1); @@ -277,12 +274,13 @@ public function testImportExportFavorites() { $status = $resp->getStatus(); $this->assertEquals(200, $status); $data = $resp->getData(); - $this->assertEquals(27, count($data)); + $this->assertCount(27, $data); $nbFavorites = count($data); $categoryCount = []; foreach ($data as $fav) { $categoryCount[$fav['category']] = isset($categoryCount[$fav['category']]) ? ($categoryCount[$fav['category']] + 1) : 1; } + $categories = array_keys($categoryCount); // import errors @@ -309,16 +307,17 @@ public function testImportExportFavorites() { // parse xml and compare number of favorite for each category $xmLData = $userfolder->get($exportPath)->getContent(); - $xml = simplexml_load_string($xmLData); + $xml = simplexml_load_string((string)$xmLData); $wpts = $xml->wpt; - $this->assertEquals($nbFavorites, count($wpts)); + $this->assertCount($nbFavorites, $wpts); $categoryCountExport = []; foreach ($wpts as $wpt) { $cat = (string)$wpt->type[0]; $categoryCountExport[$cat] = isset($categoryCountExport[$cat]) ? ($categoryCountExport[$cat] + 1) : 1; } + foreach ($categoryCount as $cat => $nb) { - $this->assertEquals($categoryCountExport[$cat], $nb); + $this->assertSame($categoryCountExport[$cat], $nb); } // export error @@ -342,12 +341,14 @@ public function testImportExportFavorites() { $data = $resp->getData(); $favIds = []; foreach ($data as $fav) { - array_push($favIds, $fav['id']); + $favIds[] = $fav['id']; } + $resp = $this->favoritesController->deleteFavorites($favIds); // and then try to export $resp = $this->favoritesController->exportFavorites($categories, null, null, true); + $status = $resp->getStatus(); $this->assertEquals(400, $status); $data = $resp->getData(); @@ -356,7 +357,7 @@ public function testImportExportFavorites() { - public function testEditFavorites() { + public function testEditFavorites(): void { // valid edition $resp = $this->favoritesController->addFavorite('a', 3.1, 4.1, 'cat1', null, null); $favId = $resp->getData()['id']; @@ -374,13 +375,14 @@ public function testEditFavorites() { if ($fav['id'] === $favId) { $seen = true; $this->assertEquals('aa', $fav['name']); - $this->assertEquals(3.2, $fav['lat']); - $this->assertEquals(4.2, $fav['lng']); + $this->assertEqualsWithDelta(3.2, $fav['lat'], PHP_FLOAT_EPSILON); + $this->assertEqualsWithDelta(4.2, $fav['lng'], PHP_FLOAT_EPSILON); $this->assertEquals('cat2', $fav['category']); $this->assertEquals('comment', $fav['comment']); $this->assertEquals('ext', $fav['extensions']); } } + $this->assertEquals(true, $seen); // invalid edition @@ -402,6 +404,7 @@ public function testEditFavorites() { $resp = $this->favoritesController->addFavorite('one', 3.1, 4.2, 'cat2', null, null); $resp = $this->favoritesController->renameCategories(['cat1'], 'cat1RENAMED'); + $status = $resp->getStatus(); $this->assertEquals(200, $status); $data = $resp->getData(); @@ -416,6 +419,7 @@ public function testEditFavorites() { $this->assertEquals('cat1RENAMED', $fav['category']); } } + $this->assertEquals(true, $seen); } @@ -439,12 +443,13 @@ public function testEditFavoritesMyMap(): void { if ($fav['id'] === $favId) { $seen = true; $this->assertEquals('aa', $fav['name']); - $this->assertEquals(3.2, $fav['lat']); - $this->assertEquals(4.2, $fav['lng']); + $this->assertEqualsWithDelta(3.2, $fav['lat'], PHP_FLOAT_EPSILON); + $this->assertEqualsWithDelta(4.2, $fav['lng'], PHP_FLOAT_EPSILON); $this->assertEquals('cat2', $fav['category']); $this->assertEquals('comment', $fav['comment']); } } + $this->assertEquals(true, $seen); // invalid edition @@ -465,6 +470,7 @@ public function testEditFavoritesMyMap(): void { $resp = $this->favoritesController->addFavorite('one', 3.1, 4.2, 'cat2', null, null, $myMapId); $resp = $this->favoritesController->renameCategories(['cat1'], 'cat1RENAMED', $myMapId); + $status = $resp->getStatus(); $this->assertEquals(200, $status); $data = $resp->getData(); @@ -479,10 +485,11 @@ public function testEditFavoritesMyMap(): void { $this->assertEquals('cat1RENAMED', $fav['category']); } } + $this->assertEquals(true, $seen); } - public function testShareUnShareCategory() { + public function testShareUnShareCategory(): void { $categoryName = 'test3458565'; $id = $this->favoritesController @@ -501,7 +508,7 @@ public function testShareUnShareCategory() { $this->assertTrue($response2->getData()['did_exist']); } - public function testShareUnShareCategoryNotAuthorized() { + public function testShareUnShareCategoryNotAuthorized(): void { $categoryName = 'test3458565'; $id = $this->favoritesController2 @@ -517,7 +524,7 @@ public function testShareUnShareCategoryNotAuthorized() { $this->assertEquals(Http::STATUS_BAD_REQUEST, $response2->getStatus()); } - public function testShareUnShareNonExistentCategory() { + public function testShareUnShareNonExistentCategory(): void { $categoryName = 'non_existent'; $response1 = $this->favoritesController->shareCategory($categoryName); @@ -529,17 +536,14 @@ public function testShareUnShareNonExistentCategory() { $this->assertEquals(Http::STATUS_BAD_REQUEST, $response2->getStatus()); } - public function testGetSharedCategories() { + public function testGetSharedCategories(): void { $categoryNames = ['test345456', 'test2345465', 'test65765']; $ids = []; foreach ($categoryNames as $categoryName) { - array_push( - $ids, - $this->favoritesController - ->addFavorite('Test', 0, 0, $categoryName, '', null) - ->getData()['id'] - ); + $ids[] = $this->favoritesController + ->addFavorite('Test', 0, 0, $categoryName, '', null) + ->getData()['id']; $this->favoritesController->shareCategory($categoryName); } @@ -547,9 +551,7 @@ public function testGetSharedCategories() { $this->assertIsArray($categories->getData()); - $mappedCategories = array_map(function ($el) { - return $el->getCategory(); - }, $categories->getData()); + $mappedCategories = array_map(fn ($el) => $el->getCategory(), $categories->getData()); foreach ($categoryNames as $categoryName) { $this->assertContains($categoryName, $mappedCategories); @@ -564,7 +566,7 @@ public function testGetSharedCategories() { } } - public function testFavoriteShareIsRenamedCorrectly() { + public function testFavoriteShareIsRenamedCorrectly(): void { $categoryName = 'test03059035'; $newCategoryName = 'test097876'; @@ -578,9 +580,7 @@ public function testFavoriteShareIsRenamedCorrectly() { $shares = $this->favoritesController->getSharedCategories()->getData(); - $shareNames = array_map(function ($el) { - return $el->getCategory(); - }, $shares); + $shareNames = array_map(fn ($el) => $el->getCategory(), $shares); $this->favoritesController->deleteFavorite($id); $this->favoritesController->unShareCategory($newCategoryName); diff --git a/tests/Unit/Controller/PageControllerTest.php b/tests/Unit/Controller/PageControllerTest.php index 3a24815c9..d9325f5eb 100644 --- a/tests/Unit/Controller/PageControllerTest.php +++ b/tests/Unit/Controller/PageControllerTest.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Services\IInitialState; use OCP\EventDispatcher\IEventDispatcher; -use OCP\IConfig; +use OCP\IAppConfig; use OCP\IRequest; use OCP\IURLGenerator; -use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; -class PageControllerTest extends \PHPUnit\Framework\TestCase { +final class PageControllerTest extends TestCase { private PageController $controller; + private string $userId = 'john'; - private IConfig&MockObject $config; - private IInitialState&MockObject $initialState; - private IEventDispatcher&MockObject $eventDispatcher; - private IURLGenerator&MockObject $urlGenerator; protected function setUp(): void { - /** @var IRequest&MockObject */ $request = $this->createMock(IRequest::class); - $this->config = $this->createMock(IConfig::class); - $this->initialState = $this->createMock(IInitialState::class); - $this->eventDispatcher = $this->createMock(IEventDispatcher::class); - $this->urlGenerator = $this->createMock(IURLGenerator::class); + $appConfig = $this->createMock(IAppConfig::class); + $initialState = $this->createMock(IInitialState::class); + $eventDispatcher = $this->createMock(IEventDispatcher::class); + $urlGenerator = $this->createMock(IURLGenerator::class); $this->controller = new PageController( 'maps', $request, $this->userId, - $this->eventDispatcher, - $this->config, - $this->initialState, - $this->urlGenerator, + $eventDispatcher, + $appConfig, + $initialState, + $urlGenerator, ); } - public function testIndex() { + public function testIndex(): void { $result = $this->controller->index(); $this->assertEquals('main', $result->getTemplateName()); - $this->assertTrue($result instanceof TemplateResponse); + $this->assertInstanceOf(TemplateResponse::class, $result); } - public function testOpenGeoLink() { + public function testOpenGeoLink(): void { $result = $this->controller->openGeoLink('geo:1.1,2.2'); $this->assertEquals('main', $result->getTemplateName()); - $this->assertTrue($result instanceof TemplateResponse); + $this->assertInstanceOf(TemplateResponse::class, $result); } } diff --git a/tests/Unit/Controller/PhotosControllerTest.php b/tests/Unit/Controller/PhotosControllerTest.php index d73031588..588251e9a 100644 --- a/tests/Unit/Controller/PhotosControllerTest.php +++ b/tests/Unit/Controller/PhotosControllerTest.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; use OCA\Maps\AppInfo\Application; @@ -20,112 +21,91 @@ use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Files\IRootFolder; use OCP\ICacheFactory; -use OCP\IConfig; -use OCP\IServerContainer; +use OCP\IDBConnection; +use OCP\IGroupManager; +use OCP\IUserManager; use OCP\L10N\IFactory; use OCP\Server; +use OCP\Share\IManager; +use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; -class PhotosControllerTest extends \PHPUnit\Framework\TestCase { - private $appName; - private $request; - private $contacts; +final class PhotosControllerTest extends TestCase { private $container; - private $config; - private $app; - private $photosController; - private $photosController2; - private $utilsController; - private $photoFileService; + private PhotosController $photosController; + + private PhotofilesService $photoFileService; + private $GeoPhotosService; public static function setUpBeforeClass(): void { $app = new Application(); $c = $app->getContainer(); - $user = $c->getServer()->getUserManager()->get('test'); - $user2 = $c->getServer()->getUserManager()->get('test2'); - $user3 = $c->getServer()->getUserManager()->get('test3'); - $group = $c->getServer()->getGroupManager()->get('group1test'); - $group2 = $c->getServer()->getGroupManager()->get('group2test'); + $user = $c->get(IUserManager::class)->get('test'); + $user2 = $c->get(IUserManager::class)->get('test2'); + $user3 = $c->get(IUserManager::class)->get('test3'); + $group = $c->get(IGroupManager::class)->get('group1test'); + $group2 = $c->get(IGroupManager::class)->get('group2test'); // CREATE DUMMY USERS if ($user === null) { - $u1 = $c->getServer()->getUserManager()->createUser('test', 'tatotitoTUTU'); + $u1 = $c->get(IUserManager::class)->createUser('test', 'tatotitoTUTU'); $u1->setEMailAddress('toto@toto.net'); } + if ($user2 === null) { - $u2 = $c->getServer()->getUserManager()->createUser('test2', 'plopinoulala000'); + $c->get(IUserManager::class)->createUser('test2', 'plopinoulala000'); } - if ($user2 === null) { - $u3 = $c->getServer()->getUserManager()->createUser('test3', 'yeyeahPASSPASS'); + + if ($user3 === null) { + $c->get(IUserManager::class)->createUser('test3', 'yeyeahPASSPASS'); } + if ($group === null) { - $c->getServer()->getGroupManager()->createGroup('group1test'); - $u1 = $c->getServer()->getUserManager()->get('test'); - $c->getServer()->getGroupManager()->get('group1test')->addUser($u1); + $c->get(IGroupManager::class)->createGroup('group1test'); + $u1 = $c->get(IUserManager::class)->get('test'); + $c->get(IGroupManager::class)->get('group1test')->addUser($u1); } + if ($group2 === null) { - $c->getServer()->getGroupManager()->createGroup('group2test'); - $u2 = $c->getServer()->getUserManager()->get('test2'); - $c->getServer()->getGroupManager()->get('group2test')->addUser($u2); + $c->get(IGroupManager::class)->createGroup('group2test'); + $u2 = $c->get(IUserManager::class)->get('test2'); + $c->get(IGroupManager::class)->get('group2test')->addUser($u2); } } protected function setUp(): void { - $this->appName = 'maps'; - $this->request = $this->getMockBuilder('\OCP\IRequest') - ->disableOriginalConstructor() - ->getMock(); - $this->contacts = $this->getMockBuilder('OCP\Contacts\IManager') - ->disableOriginalConstructor() - ->getMock(); - - $this->app = new Application(); - $this->container = $this->app->getContainer(); + $appName = 'maps'; + $request = $this->createMock('\OCP\IRequest'); + + $app = new Application(); + $this->container = $app->getContainer(); $c = $this->container; - $this->config = $c->get(IConfig::class); - $this->rootFolder = $c->get(IRootFolder::class); + $rootFolder = $c->get(IRootFolder::class); $this->GeoPhotosService = $c->get(GeoPhotoService::class); $this->photoFileService = new PhotoFilesService( $c->get(LoggerInterface::class), $c->get(ICacheFactory::class), - $this->rootFolder, + $rootFolder, $c->get(IFactory::class)->get($c->get('AppName')), $c->get(GeophotoMapper::class), - $c->get(\OCP\Share\IManager::class), + $c->get(IManager::class), $c->get(IJobList::class) ); $this->photosController = new PhotosController( - $this->appName, - $this->request, + $appName, + $request, $this->GeoPhotosService, $this->photoFileService, - $this->rootFolder, - 'test' - ); - - $this->photosController2 = new PhotosController( - $this->appName, - $this->request, - $c->get(GeoPhotoService::class), - $this->photoFileService, - $this->rootFolder, - 'test2' - ); - - $this->utilsController = new UtilsController( - $this->appName, - $this->request, - $c->get(IServerContainer::class)->getConfig(), - $this->rootFolder, + $rootFolder, 'test' ); @@ -135,39 +115,39 @@ protected function setUp(): void { $file = $userfolder->get('nc.jpg'); $file->delete(); } + if ($userfolder->nodeExists('nut.jpg')) { $file = $userfolder->get('nut.jpg'); $file->delete(); } + // delete db - $qb = Server::get(\OCP\IDBConnection::class)->getQueryBuilder(); + $qb = Server::get(IDBConnection::class)->getQueryBuilder(); $qb->delete('maps_photos') ->where( $qb->expr()->eq('user_id', $qb->createNamedParameter('test', IQueryBuilder::PARAM_STR)) ); - $req = $qb->executeStatement(); + $qb->executeStatement(); } public static function tearDownAfterClass(): void { //$app = new Application(); //$c = $app->getContainer(); - //$user = $c->getServer()->getUserManager()->get('test'); + //$user = $c->get(IUserManager::class)->get('test'); //$user->delete(); - //$user = $c->getServer()->getUserManager()->get('test2'); + //$user = $c->get(IUserManager::class)->get('test2'); //$user->delete(); - //$user = $c->getServer()->getUserManager()->get('test3'); + //$user = $c->get(IUserManager::class)->get('test3'); //$user->delete(); - //$c->getServer()->getGroupManager()->get('group1test')->delete(); - //$c->getServer()->getGroupManager()->get('group2test')->delete(); + //$c->get(IGroupManager::class)->get('group1test')->delete(); + //$c->get(IGroupManager::class)->get('group2test')->delete(); } protected function tearDown(): void { // in case there was a failure and something was not deleted } - public function testAddGetPhotos() { - $c = $this->app->getContainer(); - + public function testAddGetPhotos(): void { $userfolder = $this->container->get(IRootFolder::class)->getUserFolder('test'); $filename = 'tests/test_files/nc.jpg'; @@ -184,6 +164,7 @@ public function testAddGetPhotos() { $file->move($userfolder->getPath() . '/nc.jpg'); $file = $userfolder->get('nc.jpg'); $file->touch(); + $this->photoFileService->addPhotoNow($file, 'test'); $filename = 'tests/test_files/nut.jpg'; @@ -240,7 +221,7 @@ public function testAddGetPhotos() { $status = $resp->getStatus(); $this->assertEquals(200, $status); $data = $resp->getData(); - $this->assertEquals(0, count($data)); + $this->assertCount(0, $data); $file->delete(); // non localized without track @@ -302,7 +283,7 @@ public function testAddGetPhotos() { $status = $resp->getStatus(); $this->assertEquals(200, $status); $data = $resp->getData(); - $this->assertEquals(0, count($data)); + $this->assertCount(0, $data); $file->delete(); //Test myMap @@ -312,7 +293,7 @@ public function testAddGetPhotos() { $status = $resp->getStatus(); $this->assertEquals(200, $status); $data = $resp->getData(); - $this->assertEquals(0, count($data)); + $this->assertCount(0, $data); $file->delete(); // place photos diff --git a/tests/Unit/Controller/PublicFavoritePageControllerTest.php b/tests/Unit/Controller/PublicFavoritePageControllerTest.php index dffc93f89..77ecf5bcc 100644 --- a/tests/Unit/Controller/PublicFavoritePageControllerTest.php +++ b/tests/Unit/Controller/PublicFavoritePageControllerTest.php @@ -1,5 +1,7 @@ * @@ -21,85 +23,74 @@ * along with this program. If not, see . * */ - namespace OCA\Maps\Controller; -use OC; -use OC\AppFramework\Http; use OCA\Maps\AppInfo\Application; use OCA\Maps\DB\FavoriteShareMapper; use OCA\Maps\Service\FavoritesService; +use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\TemplateResponse; -use OCP\AppFramework\IAppContainer; -use OCP\IServerContainer; +use OCP\Files\IRootFolder; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\IRequest; +use OCP\ISession; +use OCP\L10N\IFactory; +use OCP\Security\ISecureRandom; +use OCP\Server; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; -class PublicFavoritePageControllerTest extends TestCase { - /* @var PublicFavoritePageController */ - private $publicPageController; - - private $config; +final class PublicFavoritePageControllerTest extends TestCase { + private PublicFavoritePageController $publicPageController; - /* @var Application */ - private $app; + private FavoritesService $favoritesService; - /* @var IAppContainer */ - private $container; - - /* @var FavoritesService */ - private $favoritesService; - - /* @var FavoriteShareMapper */ - private $favoriteShareMapper; + private FavoriteShareMapper $favoriteShareMapper; protected function setUp(): void { // Begin transaction - $db = \OCP\Server::get(\OCP\IDBConnection::class); + $db = Server::get(IDBConnection::class); $db->beginTransaction(); - $this->app = new Application(); + $app = new Application(); - $this->container = $this->app->getContainer(); - $container = $this->container; + $container = $app->getContainer(); - $appName = $container->query('appName'); + $appName = $container->get('appName'); $this->favoritesService = new FavoritesService( - $container->query(IServerContainer::class)->get(LoggerInterface::class), - $container->query(IServerContainer::class)->getL10N($appName), - $container->query(IServerContainer::class)->getSecureRandom(), - $container->query(\OCP\IDBConnection::class) + $container->get(LoggerInterface::class), + $container->get(IFactory::class)->get($appName), + $container->get(IDBConnection::class) ); $this->favoriteShareMapper = new FavoriteShareMapper( - $container->query(\OCP\IDBConnection::class), - $container->query(IServerContainer::class)->getSecureRandom(), - $container->query(IServerContainer::class)->getRootFolder() + $container->get(IDBConnection::class), + $container->get(ISecureRandom::class), + $container->get(IRootFolder::class) ); - $requestMock = $this->getMockBuilder('OCP\IRequest')->getMock(); - $sessionMock = $this->getMockBuilder('OCP\ISession')->getMock(); - - $this->config = $container->query(IServerContainer::class)->getConfig(); + $requestMock = $this->createMock(IRequest::class); + $sessionMock = $this->createMock(ISession::class); $this->publicPageController = new PublicFavoritePageController( $appName, $requestMock, $sessionMock, - $this->config, + $container->get(IConfig::class), $this->favoriteShareMapper ); } protected function tearDown(): void { // Rollback transaction - $db = OC::$server->query(\OCP\IDBConnection::class); + $db = Server::get(IDBConnection::class); $db->rollBack(); } - public function testSharedFavoritesCategory() { + public function testSharedFavoritesCategory(): void { $categoryName = 'test908780'; $testUserName = 'test'; @@ -110,14 +101,14 @@ public function testSharedFavoritesCategory() { $result = $this->publicPageController->sharedFavoritesCategory($share->getToken()); // Assertions - $this->assertTrue($result instanceof TemplateResponse); + $this->assertInstanceOf(TemplateResponse::class, $result); $this->assertEquals('public/favorites_index', $result->getTemplateName()); } - public function testAccessRestrictionsForSharedFavoritesCategory() { + public function testAccessRestrictionsForSharedFavoritesCategory(): void { $result = $this->publicPageController->sharedFavoritesCategory('test8348985'); - $this->assertTrue($result instanceof DataResponse); + $this->assertInstanceOf(DataResponse::class, $result); $this->assertEquals(Http::STATUS_NOT_FOUND, $result->getStatus()); } } diff --git a/tests/Unit/Controller/PublicFavoritesApiControllerTest.php b/tests/Unit/Controller/PublicFavoritesApiControllerTest.php index a8243b6fe..655abc519 100644 --- a/tests/Unit/Controller/PublicFavoritesApiControllerTest.php +++ b/tests/Unit/Controller/PublicFavoritesApiControllerTest.php @@ -1,5 +1,7 @@ * @@ -21,13 +23,12 @@ * along with this program. If not, see . * */ - namespace OCA\Maps\Controller; -use OC\AppFramework\Http; use OCA\Maps\AppInfo\Application; use OCA\Maps\DB\FavoriteShareMapper; use OCA\Maps\Service\FavoritesService; +use OCP\AppFramework\Http; use OCP\Files\IRootFolder; use OCP\IDBConnection; use OCP\IRequest; @@ -38,9 +39,11 @@ use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; -class PublicFavoritesApiControllerTest extends TestCase { +final class PublicFavoritesApiControllerTest extends TestCase { private PublicFavoritesApiController $publicFavoritesApiController; + private FavoritesService $favoritesService; + private FavoriteShareMapper $favoriteShareMapper; protected function setUp(): void { @@ -106,7 +109,7 @@ public function testGetFavorites(): void { $this->assertEquals($categoryName, $data['share']->getCategory()); $this->assertEquals($share->getToken(), $data['share']->getToken()); - $this->assertEquals(1, count($data['favorites'])); + $this->assertCount(1, $data['favorites']); $el = $data['favorites'][0]; $this->assertEquals('Test1', $el['name']); diff --git a/tests/Unit/Controller/TracksControllerTest.php b/tests/Unit/Controller/TracksControllerTest.php index c62d1ba88..94046bea2 100644 --- a/tests/Unit/Controller/TracksControllerTest.php +++ b/tests/Unit/Controller/TracksControllerTest.php @@ -1,5 +1,7 @@ * @copyright Julien Veyssier 2019 */ - namespace OCA\Maps\Controller; use OCA\Maps\AppInfo\Application; @@ -23,59 +24,60 @@ use OCP\IUserManager; use OCP\Server; use OCP\Share\IManager as IShareManager; -use PHPUnit\Framework\MockObject\MockObject; -use Psr\Container\ContainerInterface; +use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; -class TracksControllerTest extends \PHPUnit\Framework\TestCase { - private string $appName; - private IRequest&MockObject $request; - private ContainerInterface $container; +final class TracksControllerTest extends TestCase { + private IRootFolder $rootFolder; + private Application $app; private TracksController $tracksController; + private TracksService $tracksService; public static function setUpBeforeClass(): void { $app = new Application(); $c = $app->getContainer(); - $user = $c->get(IUserManager::class)->get('test'); + $user1 = $c->get(IUserManager::class)->get('test'); $user2 = $c->get(IUserManager::class)->get('test2'); $user3 = $c->get(IUserManager::class)->get('test3'); $group = $c->get(IGroupManager::class)->get('group1test'); $group2 = $c->get(IGroupManager::class)->get('group2test'); // CREATE DUMMY USERS - if ($user === null) { - $u1 = $c->get(IUserManager::class)->createUser('test', 'tatotitoTUTU'); - $u1->setEMailAddress('toto@toto.net'); + if ($user1 === null) { + $user1 = $c->get(IUserManager::class)->createUser('test', 'tatotitoTUTU'); + $user1->setEMailAddress('toto@toto.net'); } + if ($user2 === null) { - $u2 = $c->get(IUserManager::class)->createUser('test2', 'plopinoulala000'); + $user2 = $c->get(IUserManager::class)->createUser('test2', 'plopinoulala000'); } - if ($user2 === null) { - $u3 = $c->get(IUserManager::class)->createUser('test3', 'yeyeahPASSPASS'); + + if ($user3 === null) { + $user3 = $c->get(IUserManager::class)->createUser('test3', 'yeyeahPASSPASS'); } + if ($group === null) { $c->get(IGroupManager::class)->createGroup('group1test'); - $u1 = $c->get(IUserManager::class)->get('test'); - $c->get(IGroupManager::class)->get('group1test')->addUser($u1); + $c->get(IGroupManager::class)->get('group1test')->addUser($user1); } + if ($group2 === null) { $c->get(IGroupManager::class)->createGroup('group2test'); - $u2 = $c->get(IUserManager::class)->get('test2'); - $c->get(IGroupManager::class)->get('group2test')->addUser($u2); + $c->get(IGroupManager::class)->get('group2test')->addUser($user2); } } protected function setUp(): void { - $this->appName = 'maps'; - $this->request = $this->createMock(IRequest::class); + $appName = 'maps'; + $request = $this->createMock(IRequest::class); $this->app = new Application(); - $this->container = $this->app->getContainer(); - $c = $this->container; + $container = $this->app->getContainer(); + $c = $container; $this->rootFolder = $c->get(IRootFolder::class); @@ -87,8 +89,8 @@ protected function setUp(): void { ); $this->tracksController = new TracksController( - $this->appName, - $this->request, + $appName, + $request, $c->get(IL10N::class), $c->get(TracksService::class), $c->get(IRootFolder::class), @@ -103,13 +105,14 @@ protected function setUp(): void { $file = $userfolder->get('testFile1.gpx'); $file->delete(); } + // delete db - $qb = Server::get(\OCP\IDBConnection::class)->getQueryBuilder(); + $qb = Server::get(IDBConnection::class)->getQueryBuilder(); $qb->delete('maps_tracks') ->where( $qb->expr()->eq('user_id', $qb->createNamedParameter('test', IQueryBuilder::PARAM_STR)) ); - $req = $qb->executeStatement(); + $qb->executeStatement(); } public static function tearDownAfterClass(): void { @@ -127,7 +130,7 @@ public static function tearDownAfterClass(): void { protected function tearDown(): void { // in case there was a failure and something was not deleted - $c = $this->app->getContainer(); + $this->app->getContainer(); $userfolder = $this->rootFolder->getUserFolder('test'); // delete files @@ -135,16 +138,17 @@ protected function tearDown(): void { $file = $userfolder->get('testFile1.gpx'); $file->delete(); } + // delete db - $qb = Server::get(\OCP\IDBConnection::class)->getQueryBuilder(); + $qb = Server::get(IDBConnection::class)->getQueryBuilder(); $qb->delete('maps_tracks') ->where( $qb->expr()->eq('user_id', $qb->createNamedParameter('test', IQueryBuilder::PARAM_STR)) ); - $req = $qb->executeStatement(); + $qb->executeStatement(); } - public function testAddGetTracks() { + public function testAddGetTracks(): void { $userfolder = $this->rootFolder->getUserFolder('test'); $filename = 'tests/test_files/testFile1.gpx'; @@ -164,13 +168,14 @@ public function testAddGetTracks() { $this->assertEquals(200, $status); $data = $resp->getData(); $foundTestFile = false; - foreach ($data as $k => $v) { + foreach ($data as $v) { if ($v['file_path'] === '/testFile1.gpx') { $foundTestFile = true; break; } } - $this->assertTrue(count($data) > 0); + + $this->assertGreaterThan(0, count($data)); $this->assertTrue($foundTestFile); foreach ($this->tracksService->rescan('test') as $path) { @@ -184,7 +189,7 @@ public function testAddGetTracks() { $foundTestFile = false; //var_dump($data); $trackId = null; - foreach ($data as $k => $v) { + foreach ($data as $v) { if ($v['file_path'] === '/testFile1.gpx') { $foundTestFile = true; $trackId = $v['id']; @@ -192,6 +197,7 @@ public function testAddGetTracks() { break; } } + $this->assertEquals(true, count($data) > 0); $this->assertEquals(true, $foundTestFile); @@ -202,7 +208,7 @@ public function testAddGetTracks() { $data = $resp->getData(); $this->assertEquals(true, $content1 === $data['content']); $meta = $data['metadata']; - $this->assertEquals(true, strlen($meta) > 0); + $this->assertEquals(true, (string)$meta !== ''); // to get stored metadata $resp = $this->tracksController->getTrackFileContent($trackId); @@ -232,13 +238,14 @@ public function testAddGetTracks() { $this->assertEquals(200, $status); $data = $resp->getData(); $foundTestFile = false; - foreach ($data as $k => $v) { + foreach ($data as $v) { if ($v['file_path'] === '/testFile1.gpx') { $foundTestFile = true; $this->assertEquals(true, $v['color'] === '#002244'); break; } } + $this->assertEquals(true, count($data) > 0); $this->assertEquals(true, $foundTestFile); diff --git a/tests/Unit/Helper/ExifGeoDataTest.php b/tests/Unit/Helper/ExifGeoDataTest.php index 29d3c35d0..fbfc5a6d2 100644 --- a/tests/Unit/Helper/ExifGeoDataTest.php +++ b/tests/Unit/Helper/ExifGeoDataTest.php @@ -1,51 +1,55 @@ > + */ + public static function imageWithDateAndLocationProvider(): \Iterator { + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation1.JPG', 1311984000 + 7200, 47.071717, 10.339557]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation2.JPG', 1312156800 + 7200, 46.862350, 10.916452]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation3.JPG', 1312070400 + 7200, 47.069058, 10.329370]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation4.JPG', 1312070400 + 7200, 47.059160, 10.312354]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation5.JPG', 1568101093 + 7200, 47.357735, 11.177585]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation6.JPG', 1577630208 + 3600, 50.083045, 9.986018]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation7.jpg', 1568999599 + 7200, 49.420833, 11.114444]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation8.JPG', 1501431401 + 7200, 45.306983, 10.700902]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation9.JPG', 1302998400 + 7200, 52.363055, 4.903418]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation10.JPG', 1501238375 + 7200, 46.388742, 11.266598]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation11.JPG', 1501567361 + 7200, 44.827830, 10.956387]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation12.JPG', 1501591333 + 7200, 44.528283, 11.262207]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation13.jpg', 1640083235 + 3600, 54.359561, 10.017325]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation14.jpg', 1559327910 + 7200, 52.976844, 12.988281]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation15.jpg', 1559332394 + 7200, 52.983697, 12.935217]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation16.jpeg', 1593458542 + 7200, 62.733947, 6.779617]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation17.jpeg', 1593458620 + 7200, 62.733769, 6.777794]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation18.jpeg', 1596136867 + 7200, 54.350891, 9.903506]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation19.jpeg', 1596136833 + 7200, 54.350894, 9.903505]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation20.jpeg', 1592913150 + 7200, 61.351753, 6.519107]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation21.jpg', 1653565075 + 7200, 48.704331, 8.418475]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation22.jpeg', 1593890841 + 7200, 62.735419, 7.155311]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation23.jpeg', 1592904886 + 7200, 61.217086, 6.558886]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation24.jpeg', 1592677991 + 7200, 60.427481, 6.548446]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation25.jpeg', 1592650395 + 7200, 59.860523, 6.696346]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation26.jpeg', 1592770386 + 7200, 60.594022, 6.581317]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation27.jpeg', 1592654095 + 7200, 60.033561, 6.563068]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation28.jpg', 1595326357 + 7200, 59.852992, 6.714458]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation29.jpg', 1594918175 + 7200, 57.595925, 9.976864]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation30.jpg', 1595418724 + 7200, 60.669492, 6.807386]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation31.jpg', 1594934141 + 7200, 57.801164, 8.314269]; + yield ['tests/test_files/Photos/WithDateAndLocation/imageWithDateAndLocation32.jpeg', 1595629060 + 7200, 59.598981, 9.677297]; } + /** * @dataProvider imageWithDateAndLocationProvider */ - public function testImagesWithDateAndLocation(string $path, int $date, float $lat, float $lng) { + public function testImagesWithDateAndLocation(string $path, int $date, float $lat, float $lng): void { $exif_geo_data = ExifGeoData::get($path); $exif_geo_data->validate(true); $this->assertEquals($date, $exif_geo_data->dateTaken); @@ -54,15 +58,17 @@ public function testImagesWithDateAndLocation(string $path, int $date, float $la $this->assertEqualsWithDelta($lng, $exif_geo_data->lng, 0.000005); } - public static function imageWithZeroIslandProvider(): array { - return [ - ['tests/test_files/Photos/ZeroIsland/imageZeroIsland1.JPG', 1653829180 + 7200], - ]; + /** + * @return \Iterator> + */ + public static function imageWithZeroIslandProvider(): \Iterator { + yield ['tests/test_files/Photos/ZeroIsland/imageZeroIsland1.JPG', 1653829180 + 7200]; } + /** * @dataProvider imageWithZeroIslandProvider */ - public function testImagesWithZeroIslandException(string $path, int $date) { + public function testImagesWithZeroIslandException(string $path, int $date): void { $this->expectException(ExifDataNoLocationException::class); $this->expectExceptionMessage('Zero island is not valid'); $exif_geo_data = ExifGeoData::get($path); @@ -72,12 +78,12 @@ public function testImagesWithZeroIslandException(string $path, int $date) { /** * @dataProvider imageWithZeroIslandProvider */ - public function testImagesWithZeroIslandGeoDataNull(string $path, int $date) { + public function testImagesWithZeroIslandGeoDataNull(string $path, int $date): void { $exif_geo_data = ExifGeoData::get($path); try { $exif_geo_data->validate(true); $this->assertEquals(true, false); - } catch (ExifDataNoLocationException $e) { + } catch (ExifDataNoLocationException) { $this->assertEquals($date, $exif_geo_data->dateTaken); //This is the same upto ~55cm $this->assertEqualsWithDelta(null, $exif_geo_data->lat, 0.000005); @@ -88,7 +94,7 @@ public function testImagesWithZeroIslandGeoDataNull(string $path, int $date) { /** * @dataProvider imageWithZeroIslandProvider */ - public function testImagesWithZeroIsland(string $path, int $date) { + public function testImagesWithZeroIsland(string $path, int $date): void { $exif_geo_data = ExifGeoData::get($path); $exif_geo_data->validate(false); $this->assertEquals($date, $exif_geo_data->dateTaken); diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml index a91e4890a..d907e32b3 100644 --- a/tests/psalm-baseline.xml +++ b/tests/psalm-baseline.xml @@ -1,5 +1,10 @@ - + + + + + + @@ -11,6 +16,10 @@ + + + + @@ -31,8 +40,23 @@ + + + + + + + + + + + + + + + - + @@ -45,29 +69,24 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + trk]]> + + + + + wpt]]> + + diff --git a/tests/stubs/oc_archive_archive.php b/tests/stubs/oc_archive_archive.php index f481d0545..4bdfaa68b 100644 --- a/tests/stubs/oc_archive_archive.php +++ b/tests/stubs/oc_archive_archive.php @@ -1,5 +1,7 @@ $acl - * @return list - */ - public function applyShareAcl(int $addressBookId, array $acl): array + * For shared address books the sharee is set in the ACL of the address book + * + * @param list $acl + * @return list + */ + public function applyShareAcl(int $addressBookId, array $acl): array { } diff --git a/tests/stubs/oca_dav_events_cardcreatedevent.php b/tests/stubs/oca_dav_events_cardcreatedevent.php index 7238d46b6..c9d65b321 100644 --- a/tests/stubs/oca_dav_events_cardcreatedevent.php +++ b/tests/stubs/oca_dav_events_cardcreatedevent.php @@ -19,47 +19,30 @@ class CardCreatedEvent extends Event { /** - * CardCreatedEvent constructor. - * - * @param int $addressBookId - * @param array $addressBookData - * @param array $shares - * @param array $cardData - * @since 20.0.0 - */ - public function __construct(int $addressBookId, array $addressBookData, array $shares, array $cardData) + * @since 20.0.0 + */ + public function getAddressBookId(): int { } /** - * @return int - * @since 20.0.0 - */ - public function getAddressBookId(): int + * @since 20.0.0 + */ + public function getAddressBookData(): array { } /** - * @return array - * @since 20.0.0 - */ - public function getAddressBookData(): array + * @since 20.0.0 + */ + public function getShares(): array { } /** - * @return array - * @since 20.0.0 - */ - public function getShares(): array - { - } - - /** - * @return array - * @since 20.0.0 - */ - public function getCardData(): array + * @since 20.0.0 + */ + public function getCardData(): array { } } diff --git a/tests/stubs/oca_dav_events_carddeletedevent.php b/tests/stubs/oca_dav_events_carddeletedevent.php index f1f9cd84b..1b3f2e158 100644 --- a/tests/stubs/oca_dav_events_carddeletedevent.php +++ b/tests/stubs/oca_dav_events_carddeletedevent.php @@ -19,47 +19,30 @@ class CardDeletedEvent extends Event { /** - * CardDeletedEvent constructor. - * - * @param int $addressBookId - * @param array $addressBookData - * @param array $shares - * @param array $cardData - * @since 20.0.0 - */ - public function __construct(int $addressBookId, array $addressBookData, array $shares, array $cardData) + * @since 20.0.0 + */ + public function getAddressBookId(): int { } /** - * @return int - * @since 20.0.0 - */ - public function getAddressBookId(): int + * @since 20.0.0 + */ + public function getAddressBookData(): array { } /** - * @return array - * @since 20.0.0 - */ - public function getAddressBookData(): array + * @since 20.0.0 + */ + public function getShares(): array { } /** - * @return array - * @since 20.0.0 - */ - public function getShares(): array - { - } - - /** - * @return array - * @since 20.0.0 - */ - public function getCardData(): array + * @since 20.0.0 + */ + public function getCardData(): array { } } diff --git a/tests/stubs/oca_dav_events_cardupdatedevent.php b/tests/stubs/oca_dav_events_cardupdatedevent.php index 6bdfcaba5..d43c8e4cd 100644 --- a/tests/stubs/oca_dav_events_cardupdatedevent.php +++ b/tests/stubs/oca_dav_events_cardupdatedevent.php @@ -19,47 +19,30 @@ class CardUpdatedEvent extends Event { /** - * CardUpdatedEvent constructor. - * - * @param int $addressBookId - * @param array $addressBookData - * @param array $shares - * @param array $cardData - * @since 20.0.0 - */ - public function __construct(int $addressBookId, array $addressBookData, array $shares, array $cardData) + * @since 20.0.0 + */ + public function getAddressBookId(): int { } /** - * @return int - * @since 20.0.0 - */ - public function getAddressBookId(): int + * @since 20.0.0 + */ + public function getAddressBookData(): array { } /** - * @return array - * @since 20.0.0 - */ - public function getAddressBookData(): array + * @since 20.0.0 + */ + public function getShares(): array { } /** - * @return array - * @since 20.0.0 - */ - public function getShares(): array - { - } - - /** - * @return array - * @since 20.0.0 - */ - public function getCardData(): array + * @since 20.0.0 + */ + public function getCardData(): array { } } diff --git a/tests/stubs/oca_files_sharing_event_beforetemplaterenderedevent.php b/tests/stubs/oca_files_sharing_event_beforetemplaterenderedevent.php index 60b36908b..47d845735 100644 --- a/tests/stubs/oca_files_sharing_event_beforetemplaterenderedevent.php +++ b/tests/stubs/oca_files_sharing_event_beforetemplaterenderedevent.php @@ -23,13 +23,6 @@ class BeforeTemplateRenderedEvent extends Event { */ public const SCOPE_PUBLIC_SHARE_AUTH = 'publicShareAuth'; - /** - * @since 20.0.0 - */ - public function __construct(IShare $share, ?string $scope = null) - { - } - /** * @since 20.0.0 */ diff --git a/vendor-bin/psalm/composer.json b/vendor-bin/psalm/composer.json index d156c448e..dd96fec1d 100644 --- a/vendor-bin/psalm/composer.json +++ b/vendor-bin/psalm/composer.json @@ -6,7 +6,7 @@ }, "require-dev": { "doctrine/dbal": "^3.10.0", - "nextcloud/ocp": "dev-stable31", + "nextcloud/ocp": "dev-stable32", "sabre/dav": "^4.7.0", "symfony/console": "^6.4", "vimeo/psalm": "^6.10" diff --git a/vendor-bin/psalm/composer.lock b/vendor-bin/psalm/composer.lock index 1077c3b1c..69f0011ab 100644 --- a/vendor-bin/psalm/composer.lock +++ b/vendor-bin/psalm/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8ae0df6d06afb578f94b41e46fb6b4e5", + "content-hash": "8dcc41156ad04752614fc55994e6cab8", "packages": [], "packages-dev": [ { @@ -1833,16 +1833,16 @@ }, { "name": "nextcloud/ocp", - "version": "dev-stable31", + "version": "dev-stable32", "source": { "type": "git", "url": "https://github.com/nextcloud-deps/ocp.git", - "reference": "b369e02e33a1b9327eb3c4c5f639135b66e7bc8f" + "reference": "83cf79e2922fe1c969adeeac8dbb10e173a8d781" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/b369e02e33a1b9327eb3c4c5f639135b66e7bc8f", - "reference": "b369e02e33a1b9327eb3c4c5f639135b66e7bc8f", + "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/83cf79e2922fe1c969adeeac8dbb10e173a8d781", + "reference": "83cf79e2922fe1c969adeeac8dbb10e173a8d781", "shasum": "" }, "require": { @@ -1855,7 +1855,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-stable31": "31.0.0-dev" + "dev-stable32": "32.0.0-dev" } }, "notification-url": "https://packagist.org/downloads/", @@ -1875,7 +1875,7 @@ "description": "Composer package containing Nextcloud's public OCP API and the unstable NCU API", "support": { "issues": "https://github.com/nextcloud-deps/ocp/issues", - "source": "https://github.com/nextcloud-deps/ocp/tree/stable31" + "source": "https://github.com/nextcloud-deps/ocp/tree/stable32" }, "time": "2026-02-06T01:05:41+00:00" }, diff --git a/vendor-bin/rector/composer.json b/vendor-bin/rector/composer.json new file mode 100644 index 000000000..88f1e65e2 --- /dev/null +++ b/vendor-bin/rector/composer.json @@ -0,0 +1,6 @@ +{ + "require-dev": { + "rector/rector": "^2.0", + "nextcloud/rector": "^0.4.1" + } +} diff --git a/vendor-bin/rector/composer.lock b/vendor-bin/rector/composer.lock new file mode 100644 index 000000000..d053cd497 --- /dev/null +++ b/vendor-bin/rector/composer.lock @@ -0,0 +1,504 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "347262bc75027c88fa21b011f732aa31", + "packages": [], + "packages-dev": [ + { + "name": "nextcloud/ocp", + "version": "v32.0.5", + "source": { + "type": "git", + "url": "https://github.com/nextcloud-deps/ocp.git", + "reference": "a79703d9f38e964b003ae1cc805b6531d142fa93" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/a79703d9f38e964b003ae1cc805b6531d142fa93", + "reference": "a79703d9f38e964b003ae1cc805b6531d142fa93", + "shasum": "" + }, + "require": { + "php": "~8.1 || ~8.2 || ~8.3 || ~8.4", + "psr/clock": "^1.0", + "psr/container": "^2.0.2", + "psr/event-dispatcher": "^1.0", + "psr/log": "^3.0.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-stable32": "32.0.0-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "AGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Christoph Wurst", + "email": "christoph@winzerhof-wurst.at" + }, + { + "name": "Joas Schilling", + "email": "coding@schilljs.com" + } + ], + "description": "Composer package containing Nextcloud's public OCP API and the unstable NCU API", + "support": { + "issues": "https://github.com/nextcloud-deps/ocp/issues", + "source": "https://github.com/nextcloud-deps/ocp/tree/v32.0.5" + }, + "time": "2026-01-09T00:57:52+00:00" + }, + { + "name": "nextcloud/rector", + "version": "v0.4.1", + "source": { + "type": "git", + "url": "https://github.com/nextcloud-libraries/rector.git", + "reference": "9c5c78cc323537ec6dba5b3cd9c422ff9524d8cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nextcloud-libraries/rector/zipball/9c5c78cc323537ec6dba5b3cd9c422ff9524d8cf", + "reference": "9c5c78cc323537ec6dba5b3cd9c422ff9524d8cf", + "shasum": "" + }, + "require": { + "nextcloud/ocp": ">=27", + "php": "^8.1", + "rector/rector": "^2.0.4", + "webmozart/assert": "^1.11" + }, + "require-dev": { + "phpunit/phpunit": "^10.5", + "ramsey/devtools": "^2.0" + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + }, + "ramsey/devtools": { + "memory-limit": "-1", + "command-prefix": "dev" + }, + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" + } + }, + "autoload": { + "psr-4": { + "OCP\\": "vendor/nextcloud/ocp/OCP", + "Nextcloud\\Rector\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "AGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Christoph Wurst", + "email": "christoph@winzerhof-wurst.at", + "homepage": "https://wuc.me" + } + ], + "description": "Rector upgrade rules for Nextcloud", + "keywords": [ + "nextcloud", + "refactoring" + ], + "support": { + "issues": "https://github.com/nextcloud-libraries/rector/issues", + "source": "https://github.com/nextcloud-libraries/rector/tree/v0.4.1" + }, + "time": "2025-03-31T15:27:10+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "2.1.38", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dfaf1f530e1663aa167bc3e52197adb221582629", + "reference": "dfaf1f530e1663aa167bc3e52197adb221582629", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2026-01-30T17:12:46+00:00" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "rector/rector", + "version": "2.3.6", + "source": { + "type": "git", + "url": "https://github.com/rectorphp/rector.git", + "reference": "ca9ebb81d280cd362ea39474dabd42679e32ca6b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/ca9ebb81d280cd362ea39474dabd42679e32ca6b", + "reference": "ca9ebb81d280cd362ea39474dabd42679e32ca6b", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0", + "phpstan/phpstan": "^2.1.38" + }, + "conflict": { + "rector/rector-doctrine": "*", + "rector/rector-downgrade-php": "*", + "rector/rector-phpunit": "*", + "rector/rector-symfony": "*" + }, + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" + }, + "bin": [ + "bin/rector" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "homepage": "https://getrector.com/", + "keywords": [ + "automation", + "dev", + "migration", + "refactoring" + ], + "support": { + "issues": "https://github.com/rectorphp/rector/issues", + "source": "https://github.com/rectorphp/rector/tree/2.3.6" + }, + "funding": [ + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2026-02-06T14:25:06+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.12.1", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-date": "*", + "ext-filter": "*", + "php": "^7.2 || ^8.0" + }, + "suggest": { + "ext-intl": "", + "ext-simplexml": "", + "ext-spl": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.12.1" + }, + "time": "2025-10-29T15:56:20+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": {}, + "platform-dev": {}, + "plugin-api-version": "2.9.0" +} From 1943d952aea912a02318ba40201b54aa30a49164 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Tue, 17 Feb 2026 22:38:46 +0100 Subject: [PATCH 06/15] fix: Fix typing in photo related classes Signed-off-by: Carl Schwan --- lib/Controller/PhotosController.php | 23 ++++-- lib/DB/Geophoto.php | 6 ++ lib/DB/GeophotoMapper.php | 9 +-- lib/Service/FavoritesService.php | 4 +- lib/Service/PhotofilesService.php | 106 +++++++++++++++++----------- lib/Service/TracksService.php | 4 +- 6 files changed, 94 insertions(+), 58 deletions(-) diff --git a/lib/Controller/PhotosController.php b/lib/Controller/PhotosController.php index fb628760f..72f06ed81 100644 --- a/lib/Controller/PhotosController.php +++ b/lib/Controller/PhotosController.php @@ -87,16 +87,17 @@ public function getNonLocalizedPhotos(?int $myMapId = null, ?string $timezone = /** - * @param $paths - * @param $lats - * @param $lngs + * @param list $paths + * @param list $lats + * @param list $lngs + * @return DataResponse|array, array> * @throws NoUserException * @throws NotFoundException * @throws NotPermittedException * @throws InvalidPathException */ #[NoAdminRequired] - public function placePhotos($paths, $lats, $lngs, bool $directory = false, ?int $myMapId = null, bool $relative = false): DataResponse { + public function placePhotos(array $paths, array $lats, array $lngs, bool $directory = false, ?int $myMapId = null, bool $relative = false): DataResponse { $userFolder = $this->root->getUserFolder($this->userId); if (!is_null($myMapId)) { if ($directory) { @@ -105,7 +106,7 @@ public function placePhotos($paths, $lats, $lngs, bool $directory = false, ?int } $folder = $userFolder->getFirstNodeById($myMapId); - if (!($folder instanceof Folder)) { + if (!$folder instanceof Folder) { return new DataResponse(statusCode: Http::STATUS_BAD_REQUEST); } @@ -113,7 +114,11 @@ public function placePhotos($paths, $lats, $lngs, bool $directory = false, ?int if ($relative) { foreach ($paths as $key => $path) { $photoFile = $folder->get($path); - $paths[$key] = $userFolder->getRelativePath($photoFile->getPath()); + $path = $userFolder->getRelativePath($photoFile->getPath()); + if ($path === null) { + return new DataResponse(statusCode: Http::STATUS_BAD_REQUEST); + } + $paths[$key] = $path; } } else { // here the photo path is good, copy it in this map's folder if it's not already there @@ -122,7 +127,11 @@ public function placePhotos($paths, $lats, $lngs, bool $directory = false, ?int // is the photo in this map's folder? if ($folder->getFirstNodeById($photoFile->getId()) !== null) { $copiedFile = $photoFile->copy($folder->getPath() . '/' . $photoFile->getName()); - $paths[$key] = $userFolder->getRelativePath($copiedFile->getPath()); + $path = $userFolder->getRelativePath($copiedFile->getPath()); + if ($path === null) { + return new DataResponse(statusCode: Http::STATUS_BAD_REQUEST); + } + $paths[$key] = $path; } } } diff --git a/lib/DB/Geophoto.php b/lib/DB/Geophoto.php index eff4758ed..c240af635 100644 --- a/lib/DB/Geophoto.php +++ b/lib/DB/Geophoto.php @@ -15,6 +15,12 @@ use OCP\AppFramework\Db\Entity; +/** + * @method int getFileId() + * @method float getLat() + * @method float getLng() + * @method string getUserId() + */ class Geophoto extends Entity { protected $fileId; diff --git a/lib/DB/GeophotoMapper.php b/lib/DB/GeophotoMapper.php index d7688bcfd..bc8c956c9 100644 --- a/lib/DB/GeophotoMapper.php +++ b/lib/DB/GeophotoMapper.php @@ -44,14 +44,11 @@ public function find($id) { } /** - * @param $fileId - * @param $userId - * @return mixed|\OCP\AppFramework\Db\Entity * @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\DB\Exception */ - public function findByFileIdUserId($fileId, $userId) { + public function findByFileIdUserId(int $fileId, string $userId): Geophoto { $qb = $this->db->getQueryBuilder(); $qb->select('*') @@ -66,13 +63,11 @@ public function findByFileIdUserId($fileId, $userId) { } /** - * @param $fileId - * @return mixed|\OCP\AppFramework\Db\Entity * @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException * @throws \OCP\DB\Exception */ - public function findByFileId($fileId) { + public function findByFileId(int $fileId): Geophoto { $qb = $this->db->getQueryBuilder(); $qb->select('*') diff --git a/lib/Service/FavoritesService.php b/lib/Service/FavoritesService.php index 23a85c9d1..1622d9674 100644 --- a/lib/Service/FavoritesService.php +++ b/lib/Service/FavoritesService.php @@ -581,7 +581,7 @@ public function deleteFavoritesFromJSON($file, $ids): void { $file->putContent(json_encode($data, JSON_PRETTY_PRINT)); } - public function exportFavorites($userId, $fileHandler, $categoryList, $begin, $end, string $appVersion): void { + public function exportFavorites(?string $userId, $fileHandler, $categoryList, $begin, $end, string $appVersion): void { $qb = $this->dbconnection->getQueryBuilder(); $nbFavorites = $this->countFavorites($userId, $categoryList, $begin, $end); @@ -632,7 +632,7 @@ public function exportFavorites($userId, $fileHandler, $categoryList, $begin, $e $req = $qb->executeQuery(); while ($row = $req->fetch()) { - $name = str_replace('&', '&', $row['name']); + $name = str_replace('&', '&', $row['name'] ?? ''); $epoch = $row['date_created']; $date = ''; if (is_numeric($epoch)) { diff --git a/lib/Service/PhotofilesService.php b/lib/Service/PhotofilesService.php index b4247c372..47d495151 100644 --- a/lib/Service/PhotofilesService.php +++ b/lib/Service/PhotofilesService.php @@ -26,6 +26,7 @@ use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\Node; +use OCP\Files\NotFoundException; use OCP\Files\StorageNotAvailableException; use OCP\ICache; use OCP\ICacheFactory; @@ -248,7 +249,13 @@ public function getBackgroundJobStatus(string $userId): array { ]; } - public function setPhotosFilesCoords(string $userId, $paths, $lats, $lngs, $directory): array { + /** + * @param list $paths + * @param list $lats + * @param list $lngs + * @return list + */ + public function setPhotosFilesCoords(string $userId, $paths, $lats, $lngs, bool $directory): array { if ($directory) { return $this->setDirectoriesCoords($userId, $paths, $lats, $lngs); } @@ -256,6 +263,12 @@ public function setPhotosFilesCoords(string $userId, $paths, $lats, $lngs, $dire return $this->setFilesCoords($userId, $paths, $lats, $lngs); } + /** + * @param list $paths + * @param list $lats + * @param list $lngs + * @return list + */ private function setDirectoriesCoords(string $userId, $paths, $lats, $lngs): array { $lat = $lats[0] ?? 0; $lng = $lngs[0] ?? 0; @@ -263,24 +276,31 @@ private function setDirectoriesCoords(string $userId, $paths, $lats, $lngs): arr $done = []; foreach ($paths as $dirPath) { $cleanDirPath = str_replace(['../', '..\\'], '', $dirPath); - if ($userFolder->nodeExists($cleanDirPath)) { + try { $dir = $userFolder->get($cleanDirPath); - if ($dir instanceof Folder) { - $nodes = $dir->getDirectoryListing(); - foreach ($nodes as $node) { - if ($this->isPhoto($node) && $node->isUpdateable()) { - $photo = $this->photoMapper->findByFileIdUserId($node->getId(), $userId); - $done[] = [ - 'path' => preg_replace('/^files/', '', (string)$node->getInternalPath()), - 'lat' => $lat, - 'lng' => $lng, - 'oldLat' => $photo ? $photo->getLat() : null, - 'oldLng' => $photo ? $photo->getLng() : null, - ]; - $this->setExifCoords($node, $lat, $lng); - $this->updateByFileNow($node); - } + } catch (NotFoundException) { + continue; + } + if (!$dir instanceof Folder) { + continue; + } + $nodes = $dir->getDirectoryListing(); + foreach ($nodes as $node) { + if ($this->isPhoto($node) && $node->isUpdateable()) { + try { + $photo = $this->photoMapper->findByFileIdUserId($node->getId(), $userId); + } catch (DoesNotExistException) { + $photo = null; } + $done[] = [ + 'path' => preg_replace('/^files/', '', (string)$node->getInternalPath()), + 'lat' => $lat, + 'lng' => $lng, + 'oldLat' => $photo?->getLat(), + 'oldLng' => $photo?->getLng(), + ]; + $this->setExifCoords($node, $lat, $lng); + $this->updateByFileNow($node); } } } @@ -289,35 +309,41 @@ private function setDirectoriesCoords(string $userId, $paths, $lats, $lngs): arr } /** - * @return array{path: (array | string | null), lat: mixed, lng: mixed, oldLat: mixed, oldLng: mixed}[] + * @param list $paths + * @param list $lats + * @param list $lngs + * @return list */ - private function setFilesCoords(string $userId, $paths, array $lats, array $lngs): array { + private function setFilesCoords(string $userId, array $paths, array $lats, array $lngs): array { $userFolder = $this->root->getUserFolder($userId); $done = []; foreach ($paths as $i => $path) { - $cleanpath = str_replace(['../', '..\\'], '', $path); - if ($userFolder->nodeExists($cleanpath)) { - $file = $userFolder->get($cleanpath); - if ($file instanceof File && $this->isPhoto($file) && $file->isUpdateable()) { - $lat = (count($lats) > $i) ? $lats[$i] : $lats[0]; - $lng = (count($lngs) > $i) ? $lngs[$i] : $lngs[0]; - try { - $photo = $this->photoMapper->findByFileIdUserId($file->getId(), $userId); - } catch (DoesNotExistException) { - $photo = null; - } + $cleanPath = str_replace(['../', '..\\'], '', $path); + try { + $file = $userFolder->get($cleanPath); + } catch (NotFoundException) { + continue; + } - $done[] = [ - 'path' => preg_replace('/^files/', '', $file->getInternalPath()), - 'lat' => $lat, - 'lng' => $lng, - 'oldLat' => $photo ? $photo->getLat() : null, - 'oldLng' => $photo ? $photo->getLng() : null, - ]; - $this->setExifCoords($file, $lat, $lng); - $this->updateByFileNow($file); + if ($file instanceof File && $this->isPhoto($file) && $file->isUpdateable()) { + $lat = (count($lats) > $i) ? $lats[$i] : $lats[0]; + $lng = (count($lngs) > $i) ? $lngs[$i] : $lngs[0]; + try { + $photo = $this->photoMapper->findByFileIdUserId($file->getId(), $userId); + } catch (DoesNotExistException) { + $photo = null; } + + $done[] = [ + 'path' => preg_replace('/^files/', '', $file->getInternalPath()), + 'lat' => $lat, + 'lng' => $lng, + 'oldLat' => $photo?->getLat(), + 'oldLng' => $photo?->getLng(), + ]; + $this->setExifCoords($file, $lat, $lng); + $this->updateByFileNow($file); } } @@ -325,7 +351,7 @@ private function setFilesCoords(string $userId, $paths, array $lats, array $lngs } /** - * @return array{path: (array | string | null), lat: null, lng: null, oldLat: mixed, oldLng: mixed}[] + * @return list */ public function resetPhotosFilesCoords($userId, $paths): array { $userFolder = $this->root->getUserFolder($userId); diff --git a/lib/Service/TracksService.php b/lib/Service/TracksService.php index a7315ca80..1ab3aae1e 100644 --- a/lib/Service/TracksService.php +++ b/lib/Service/TracksService.php @@ -949,7 +949,7 @@ public function generateTrackMetadata($file): ?string { } /** - * @return mixed[] + * @return object[] */ private function getDistanceFilteredPoints($points): array { $DISTANCE_THRESHOLD = 10; @@ -959,7 +959,7 @@ private function getDistanceFilteredPoints($points): array { $distFilteredPoints[] = $points[0]; $lastPoint = $points[0]; foreach ($points as $point) { - if (distance($lastPoint, $point) >= $DISTANCE_THRESHOLD) { + if (distance((array)$lastPoint, (array)$point) >= $DISTANCE_THRESHOLD) { $distFilteredPoints[] = $point; $lastPoint = $point; } From 046cf934851264f6ae830c7f379b56b571cd15a9 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Mon, 27 Apr 2026 21:29:37 +0200 Subject: [PATCH 07/15] fix: Remove removed addAllowedChildSrcDomain call Signed-off-by: Carl Schwan --- lib/Controller/PageController.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php index 260d53508..8eac4a322 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -113,7 +113,6 @@ private function addCsp(Response $response): void { $csp->addAllowedConnectDomain('https://events.mapbox.com'); $csp->addAllowedConnectDomain('https://graphhopper.com'); - $csp->addAllowedChildSrcDomain('blob:'); $csp->addAllowedWorkerSrcDomain('blob:'); $csp->addAllowedScriptDomain('https://unpkg.com'); // allow connections to custom routing engines From 5c6211649e37fb1ccefa621ec8b7b6d25e882960 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Mon, 27 Apr 2026 22:10:52 +0200 Subject: [PATCH 08/15] feat: Port to vite instead of webpack Fix compiling the frontend for me Signed-off-by: Carl Schwan --- .babelrc.js | 11 - .eslintignore | 4 - .eslintrc.js | 20 - babel.config.js | 11 - eslint.config.js | 21 + package-lock.json | 14591 ++++++---------- package.json | 28 +- src/bootstrap.js | 9 +- src/components/Map.vue | 10 +- src/components/MapContainer.vue | 6 +- {css => src/css}/adminSettings.css | 0 {css => src/css}/icons.scss | 0 {css => src/css}/images/esri.jpg | Bin {css => src/css}/images/maps_black.svg | 0 {css => src/css}/images/marker-icon-bg.svg | 0 {css => src/css}/images/marker-icon.svg | 0 {css => src/css}/images/osm.png | Bin .../css}/merged-public-favorite-share.scss | 0 {css => src/css}/style.scss | 12 +- src/main.js | 11 +- stylelint.config.js => stylelint.config.cjs | 0 tsconfig.json | 8 +- vite.config.ts | 22 + webpack.js | 29 - 24 files changed, 5208 insertions(+), 9585 deletions(-) delete mode 100644 .babelrc.js delete mode 100644 .eslintignore delete mode 100644 .eslintrc.js delete mode 100644 babel.config.js create mode 100644 eslint.config.js rename {css => src/css}/adminSettings.css (100%) rename {css => src/css}/icons.scss (100%) rename {css => src/css}/images/esri.jpg (100%) rename {css => src/css}/images/maps_black.svg (100%) rename {css => src/css}/images/marker-icon-bg.svg (100%) rename {css => src/css}/images/marker-icon.svg (100%) rename {css => src/css}/images/osm.png (100%) rename {css => src/css}/merged-public-favorite-share.scss (100%) rename {css => src/css}/style.scss (98%) rename stylelint.config.js => stylelint.config.cjs (100%) create mode 100644 vite.config.ts delete mode 100644 webpack.js diff --git a/.babelrc.js b/.babelrc.js deleted file mode 100644 index e54da4c9a..000000000 --- a/.babelrc.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - plugins: [ - '@babel/plugin-syntax-dynamic-import', - '@babel/plugin-proposal-object-rest-spread' - ], - presets: [ - [ - '@babel/preset-env' - ] - ] -} \ No newline at end of file diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index aa1a45c5b..000000000 --- a/.eslintignore +++ /dev/null @@ -1,4 +0,0 @@ -js/ -l10n/ -src/adminSettings.js -src/utils.js diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index f68954d98..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - globals: { - appVersion: true - }, - parserOptions: { - requireConfigFile: false - }, - extends: [ - '@nextcloud' - ], - rules: { - 'no-restricted-properties': [ - 'error', - { property: 'substr', message: 'Use .slice instead of .substr.' }, - ], - 'jsdoc/require-jsdoc': 'off', - 'jsdoc/tag-lines': 'off', - 'vue/first-attribute-linebreak': 'off' - } -} diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index 60f7afa33..000000000 --- a/babel.config.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - plugins: ['@babel/plugin-syntax-dynamic-import'], - presets: [ - [ - '@babel/preset-env', - { - "modules": false - } - ] - ], -} diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 000000000..20d65a4e3 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,21 @@ +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: CC0-1.0 + */ + +import { recommended } from '@nextcloud/eslint-config' + +export default [ + ...recommended, + { + rules: { + 'no-restricted-properties': [ + 'error', + { property: 'substr', message: 'Use .slice instead of .substr.' }, + ], + 'jsdoc/require-jsdoc': 'off', + 'jsdoc/tag-lines': 'off', + 'vue/first-attribute-linebreak': 'off', + }, + }, +] diff --git a/package-lock.json b/package-lock.json index 8d49bd59c..b9939087b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,6 @@ "ua-parser-js": "^2.0.5", "vue": "^2.7.16", "vue-click-outside": "^1.1.0", - "vue-loader": "^15.11.1", "vue-material-design-icons": "^5.3.1", "vue-types": "^5.1.3", "vue2-leaflet": "^2.6.0", @@ -54,45 +53,31 @@ "vuex": "^3.6.2" }, "devDependencies": { - "@babel/plugin-proposal-object-rest-spread": "^7.20.7", - "@nextcloud/babel-config": "^1.3.0", "@nextcloud/browserslist-config": "^3.0.1", - "@nextcloud/eslint-config": "^8.4.1", + "@nextcloud/eslint-config": "^9.0.0-rc.9", "@nextcloud/stylelint-config": "^3.1.0", - "@nextcloud/webpack-vue-config": "^6.3.0", + "@nextcloud/vite-config": "^1.7.2", "@types/leaflet": "^1.9.21", "@vue/tsconfig": "^0.5.1", - "typescript": "^5.9.2" + "eslint": "^10.2.1", + "sass": "^1.99.0", + "typescript": "^5.9.2", + "vite": "^7.3.2" }, "engines": { "node": "^22.0.0", "npm": "^10.5.0" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -100,3004 +85,2777 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/compat-data": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", - "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "node_modules/@babel/code-frame/node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, "license": "MIT", + "peer": true + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/core": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", - "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", - "dev": true, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", - "peer": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.27.3", - "@babel/helpers": "^7.27.6", - "@babel/parser": "^7.28.0", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.0", - "@babel/types": "^7.28.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, "engines": { "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/eslint-parser": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.28.0.tgz", - "integrity": "sha512-N4ntErOlKvcbTt01rr5wj3y55xnIdx1ymrfIr8C2WnM1Y9glFgWaGDEULJIazOX3XM9NRzhfJ6zZnQ1sBNWU+w==", - "dev": true, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "license": "MIT", - "peer": true, "dependencies": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.1" + "@babel/types": "^7.29.0" }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + "bin": { + "parser": "bin/babel-parser.js" }, - "peerDependencies": { - "@babel/core": "^7.11.0", - "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@babel/generator": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", - "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", - "dev": true, + "node_modules/@babel/runtime": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", + "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", "license": "MIT", - "peer": true, - "dependencies": { - "@babel/parser": "^7.28.0", - "@babel/types": "^7.28.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "license": "MIT", - "peer": true, "dependencies": { - "@babel/types": "^7.27.3" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, + "node_modules/@buttercup/fetch": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@buttercup/fetch/-/fetch-0.2.1.tgz", + "integrity": "sha512-sCgECOx8wiqY8NN1xN22BqqKzXYIG2AicNLlakOAI4f0WgyLVUbAigMf8CZhBtJxdudTcB1gD5lciqi44jwJvg==", "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" + "optionalDependencies": { + "node-fetch": "^3.3.0" } }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", - "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", - "dev": true, + "node_modules/@buttercup/fetch/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "license": "MIT", - "peer": true, + "optional": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.27.1", - "semver": "^6.3.1" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" }, "engines": { - "node": ">=6.9.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", - "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "node_modules/@cacheable/memory": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.0.8.tgz", + "integrity": "sha512-FvEb29x5wVwu/Kf93IWwsOOEuhHh6dYCJF3vcKLzXc0KXIW181AOzv6ceT4ZpBHDvAfG60eqb+ekmrnLHIy+jw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "regexpu-core": "^6.2.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "@cacheable/utils": "^2.4.0", + "@keyv/bigmap": "^1.3.1", + "hookified": "^1.15.1", + "keyv": "^5.6.0" } }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", - "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "node_modules/@cacheable/memory/node_modules/@keyv/bigmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", + "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "debug": "^4.4.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.22.10" + "hashery": "^1.4.0", + "hookified": "^1.15.0" + }, + "engines": { + "node": ">= 18" }, "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "keyv": "^5.6.0" } }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "node_modules/@cacheable/memory/node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", "dev": true, "license": "MIT", "peer": true, - "engines": { - "node": ">=6.9.0" + "dependencies": { + "@keyv/serialize": "^1.1.1" } }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", - "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "node_modules/@cacheable/utils": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.4.1.tgz", + "integrity": "sha512-eiFgzCbIneyMlLOmNG4g9xzF7Hv3Mga4LjxjcSC/ues6VYq2+gUbQI8JqNuw/ZM8tJIeIaBGpswAsqV2V7ApgA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" + "hashery": "^1.5.1", + "keyv": "^5.6.0" } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "node_modules/@cacheable/utils/node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" + "@keyv/serialize": "^1.1.1" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", - "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", "peer": true, - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.3" - }, "engines": { - "node": ">=6.9.0" + "node": ">=18" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@csstools/css-tokenizer": "^3.0.4" } }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.3.tgz", + "integrity": "sha512-SH60bMfrRCJF3morcdk57WklujF4Jr/EsQUzqkarfHXEFcAR1gg7fS/chAE922Sehgzc1/+Tz5H3Ypa1HiEKrg==", "dev": true, - "license": "MIT", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "peer": true, - "dependencies": { - "@babel/types": "^7.27.1" + "peerDependencies": { + "css-tree": "^3.2.1" }, - "engines": { - "node": ">=6.9.0" + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", - "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "node_modules/@csstools/media-query-list-parser": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz", + "integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "license": "MIT", "peer": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-wrap-function": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, "engines": { - "node": ">=6.9.0" + "node": ">=18" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", "dev": true, - "license": "MIT", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "peer": true, - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, "engines": { - "node": ">=6.9.0" + "node": ">=18" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "postcss-selector-parser": "^7.0.0" } }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "node_modules/@dual-bundle/import-meta-resolve": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.2.1.tgz", + "integrity": "sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==", "dev": true, "license": "MIT", "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/JounQin" + } + }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.86.0.tgz", + "integrity": "sha512-ukZmRQ81WiTpDWO6D/cTBM7XbrNtutHKvAVnZN/8pldAwLoJArGOvkNyxPTBGsPjsoaQBJxlH+tE2TNA/92Qgw==", + "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@types/estree": "^1.0.8", + "@typescript-eslint/types": "^8.58.0", + "comment-parser": "1.4.6", + "esquery": "^1.7.0", + "jsdoc-type-pratt-parser": "~7.2.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "node_modules/@es-joy/jsdoccomment/node_modules/@typescript-eslint/types": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.1.tgz", + "integrity": "sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==", + "dev": true, "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "node_modules/@es-joy/resolve.exports": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@es-joy/resolve.exports/-/resolve.exports-1.2.0.tgz", + "integrity": "sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==", + "dev": true, "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=10" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", - "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/template": "^7.27.1", - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helpers": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", - "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.27.6" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/parser": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", - "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", - "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", - "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz", - "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", - "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "peer": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", - "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", - "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.28.0" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", - "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz", - "integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", - "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz", - "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.0.tgz", - "integrity": "sha512-IjM1IoJNw72AZFlj33Cu8X0q2XK/6AaVC3jQu+cgQ5lThWD5ajnuUAml80dqRmOhmPkTH8uAwnpMu9Rvj0LTRA==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.0" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", - "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.0" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">=6.9.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "license": "Apache-2.0", "engines": { - "node": ">=6.9.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", - "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "node_modules/@eslint/compat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-2.0.5.tgz", + "integrity": "sha512-IbHDbHJfkVNv6xjlET8AIVo/K1NQt7YT4Rp6ok/clyBGcpRx1l6gv0Rq3vBvYfPJIZt6ODf66Zq08FJNDpnzgg==", "dev": true, - "license": "MIT", - "peer": true, + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@eslint/core": "^1.2.1" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "eslint": "^8.40 || 9 || 10" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", - "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", "dev": true, - "license": "MIT", - "peer": true, + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0" + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", - "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "node_modules/@eslint/config-array/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "18 || 20 || >=22" } }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", - "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "18 || 20 || >=22" } }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, - "license": "MIT", - "peer": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + "brace-expansion": "^5.0.5" }, "engines": { - "node": ">=6.9.0" + "node": "18 || 20 || >=22" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "node_modules/@eslint/config-helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.5.tgz", + "integrity": "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==", "dev": true, - "license": "MIT", - "peer": true, + "license": "Apache-2.0", "dependencies": { - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@eslint/core": "^1.2.1" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", - "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", "dev": true, - "license": "MIT", - "peer": true, + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@types/json-schema": "^7.0.15" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", - "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "node_modules/@eslint/json": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@eslint/json/-/json-1.2.0.tgz", + "integrity": "sha512-CEFEyNgvzu8zn5QwVYDg3FaG+ZKUeUsNYitFpMYJAqoAlnw68EQgNbUfheSmexZr4n0wZPrAkPLuvsLaXO6wRw==", "dev": true, - "license": "MIT", - "peer": true, + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@eslint/core": "^1.1.1", + "@eslint/plugin-kit": "^0.6.1", + "@humanwhocodes/momoa": "^3.3.10", + "natural-compare": "^1.4.0" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "license": "Apache-2.0", "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "node_modules/@eslint/plugin-kit": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.1.tgz", + "integrity": "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==", "dev": true, - "license": "MIT", - "peer": true, + "license": "Apache-2.0", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@eslint/core": "^1.1.1", + "levn": "^0.4.1" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", - "dev": true, + "node_modules/@file-type/xml": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@file-type/xml/-/xml-0.4.3.tgz", + "integrity": "sha512-pGRmkHf+NofNy/52r06HOTsEwdNnBsFEhN6U95s33P+ezuoxZEyBTV9lOB1/Zr0So6/9vDVfWZXLpgd0fy8cOQ==", "license": "MIT", - "peer": true, "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "sax": "^1.4.1", + "strtok3": "^10.2.2" } }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", - "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", - "dev": true, + "node_modules/@floating-ui/core": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.2.tgz", + "integrity": "sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==", "license": "MIT", - "peer": true, "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@floating-ui/utils": "^0.2.10" } }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", - "dev": true, + "node_modules/@floating-ui/dom": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.2.tgz", + "integrity": "sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==", "license": "MIT", - "peer": true, "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "@floating-ui/core": "^1.7.2", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@fortawesome/fontawesome-free": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz", + "integrity": "sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==", "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=6" } }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, - "license": "MIT", - "peer": true, + "license": "Apache-2.0", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@humanfs/types": "^0.15.0" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18.18.0" } }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, - "license": "MIT", - "peer": true, + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18.18.0" } }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", - "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "license": "Apache-2.0", "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18.18.0" } }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", - "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "license": "Apache-2.0", "engines": { - "node": ">=6.9.0" + "node": ">=12.22" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz", - "integrity": "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==", + "node_modules/@humanwhocodes/momoa": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-3.3.10.tgz", + "integrity": "sha512-KWiFQpSAqEIyrTXko3hFNLeQvSK8zXlJQzhhxsyVn58WFRYXST99b3Nqnu+ttOtjds2Pl2grUHGpe2NzhPynuQ==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" - }, + "license": "Apache-2.0", "engines": { - "node": ">=6.9.0" + "node": ">=18.18" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", - "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "license": "MIT" }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", - "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", "dev": true, "license": "MIT", - "peer": true, + "peer": true + }, + "node_modules/@linusborg/vue-simple-portal": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@linusborg/vue-simple-portal/-/vue-simple-portal-0.1.5.tgz", + "integrity": "sha512-dq+oubEVW4UabBoQxmH97GiDa+F6sTomw4KcXFHnXEpw69rdkXFCxo1WzwuvWjoLiUVYJTyN1dtlUvTa50VcXg==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" + "nanoid": "^3.1.20" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "vue": "^2.6.6" } }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", - "dev": true, - "license": "MIT", + "node_modules/@mapbox/corslite": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@mapbox/corslite/-/corslite-0.0.7.tgz", + "integrity": "sha512-w/uS474VFjmqQ7fFWIMZINQM1BAQxDLuoJaZZIPES1BmeYpCtlh9MtbFxKGGDAsfvut8/HircIsVvEYRjQ+iMg==", + "license": "BSD" + }, + "node_modules/@mapbox/geojson-rewind": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", + "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", + "license": "ISC", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" + "get-stream": "^6.0.1", + "minimist": "^1.2.6" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "bin": { + "geojson-rewind": "geojson-rewind" } }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", - "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", - "dev": true, - "license": "MIT", - "peer": true, + "node_modules/@mapbox/hast-util-table-cell-style": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@mapbox/hast-util-table-cell-style/-/hast-util-table-cell-style-0.2.1.tgz", + "integrity": "sha512-LyQz4XJIdCdY/+temIhD/Ed0x/p4GAOUycpFSEK2Ads1CPKZy6b7V/2ROEtQiLLQ8soIs0xe/QAoR6kwpyW/yw==", + "license": "BSD-2-Clause", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "unist-util-visit": "^1.4.1" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=12" } }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", - "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", - "dev": true, + "node_modules/@mapbox/hast-util-table-cell-style/node_modules/unist-util-is": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz", + "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==", + "license": "MIT" + }, + "node_modules/@mapbox/hast-util-table-cell-style/node_modules/unist-util-visit": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz", + "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==", "license": "MIT", - "peer": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "unist-util-visit-parents": "^2.0.0" } }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", - "dev": true, + "node_modules/@mapbox/hast-util-table-cell-style/node_modules/unist-util-visit-parents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz", + "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==", "license": "MIT", - "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "unist-util-is": "^3.0.0" } }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.1.tgz", - "integrity": "sha512-P0QiV/taaa3kXpLY+sXla5zec4E+4t4Aqc9ggHlfZ7a2cp8/x/Gv08jfwEtn9gnnYIMvHx6aoOZ8XJL8eU71Dg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "node_modules/@mapbox/jsonlint-lines-primitives": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", + "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">= 0.6" } }, - "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", - "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "node_modules/@mapbox/mapbox-gl-supported": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-3.0.0.tgz", + "integrity": "sha512-2XghOwu16ZwPJLOFVuIOaLbN0iKMn867evzXFyf0P22dqugezfJwLmdanAgU25ITvz1TvOfVP4jsDImlDJzcWg==", + "license": "BSD-3-Clause" + }, + "node_modules/@mapbox/point-geometry": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-1.1.0.tgz", + "integrity": "sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ==", + "license": "ISC" + }, + "node_modules/@mapbox/polyline": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@mapbox/polyline/-/polyline-0.2.0.tgz", + "integrity": "sha512-GCddO0iw6AzOQqZgBmjEQI9Pgo40/yRgkTkikGctE01kNBN0ThWYuAnTD+hRWrAWMV6QJ0rNm4m8DAsaAXE7Pg==", + "bin": { + "polyline": "bin/polyline.bin.js" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": "*" } }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", - "dev": true, - "license": "MIT", - "peer": true, + "node_modules/@mapbox/tiny-sdf": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.7.tgz", + "integrity": "sha512-25gQLQMcpivjOSA40g3gO6qgiFPDpWRoMfd+G/GoppPIeP6JDaMMkMrEJnMZhKyyS6iKwVt5YKu02vCUyJM3Ug==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/vector-tile": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-2.0.4.tgz", + "integrity": "sha512-AkOLcbgGTdXScosBWwmmD7cDlvOjkg/DetGva26pIRiZPdeJYjYKarIlb4uxVzi6bwHO6EWH82eZ5Nuv4T5DUg==", + "license": "BSD-3-Clause", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "@mapbox/point-geometry": "~1.1.0", + "@types/geojson": "^7946.0.16", + "pbf": "^4.0.1" + } + }, + "node_modules/@mapbox/whoots-js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", + "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", + "license": "ISC", "engines": { - "node": ">=6.9.0" - }, + "node": ">=6.0.0" + } + }, + "node_modules/@maplibre/geojson-vt": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-5.0.4.tgz", + "integrity": "sha512-KGg9sma45S+stfH9vPCJk1J0lSDLWZgCT9Y8u8qWZJyjFlP8MNP1WGTxIMYJZjDvVT3PDn05kN1C95Sut1HpgQ==", + "license": "ISC" + }, + "node_modules/@maplibre/maplibre-gl-leaflet": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-leaflet/-/maplibre-gl-leaflet-0.1.2.tgz", + "integrity": "sha512-3BzJlaqtWxXZdK+dTjuQ/0ayOwpcT0JPNaGgnbApm5itPBENotMcZoJhRdLKljmTRyXM9/v2+eOyv/xWYVd78A==", "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@types/leaflet": "^1.9.0", + "leaflet": "^1.9.3", + "maplibre-gl": "^2.4.0 || ^3.3.1 || ^4.3.2 || ^5.0.0" } }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", - "dev": true, - "license": "MIT", - "peer": true, + "node_modules/@maplibre/maplibre-gl-style-spec": { + "version": "24.4.1", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.4.1.tgz", + "integrity": "sha512-UKhA4qv1h30XT768ccSv5NjNCX+dgfoq2qlLVmKejspPcSQTYD4SrVucgqegmYcKcmwf06wcNAa/kRd0NHWbUg==", + "license": "ISC", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/unitbezier": "^0.0.1", + "json-stringify-pretty-compact": "^4.0.0", + "minimist": "^1.2.8", + "quickselect": "^3.0.0", + "rw": "^1.3.3", + "tinyqueue": "^3.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "bin": { + "gl-style-format": "dist/gl-style-format.mjs", + "gl-style-migrate": "dist/gl-style-migrate.mjs", + "gl-style-validate": "dist/gl-style-validate.mjs" } }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", - "dev": true, - "license": "MIT", - "peer": true, + "node_modules/@maplibre/mlt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.1.6.tgz", + "integrity": "sha512-rgtY3x65lrrfXycLf6/T22ZnjTg5WgIOsptOIoCaMZy4O4UAKTyZlYY0h6v8le721pTptF94U65yMDQkug+URw==", + "license": "(MIT OR Apache-2.0)", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@mapbox/point-geometry": "^1.1.0" } }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", - "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", - "dev": true, + "node_modules/@maplibre/vt-pbf": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@maplibre/vt-pbf/-/vt-pbf-4.2.1.tgz", + "integrity": "sha512-IxZBGq/+9cqf2qdWlFuQ+ZfoMhWpxDUGQZ/poPHOJBvwMUT1GuxLo6HgYTou+xxtsOsjfbcjI8PZaPCtmt97rA==", "license": "MIT", - "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@mapbox/point-geometry": "^1.1.0", + "@mapbox/vector-tile": "^2.0.4", + "@maplibre/geojson-vt": "^5.0.4", + "@types/geojson": "^7946.0.16", + "@types/supercluster": "^7.1.3", + "pbf": "^4.0.1", + "supercluster": "^8.0.1" } }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "node_modules/@mdi/js": { + "version": "7.4.47", + "resolved": "https://registry.npmjs.org/@mdi/js/-/js-7.4.47.tgz", + "integrity": "sha512-KPnNOtm5i2pMabqZxpUz7iQf+mfrYZyKCZ8QNz85czgEt7cuHcGorWfdzUMWYA0SD+a6Hn4FmJ+YhzzzjkTZrQ==", + "license": "Apache-2.0" + }, + "node_modules/@mdi/svg": { + "version": "7.4.47", + "resolved": "https://registry.npmjs.org/@mdi/svg/-/svg-7.4.47.tgz", + "integrity": "sha512-WQ2gDll12T9WD34fdRFgQVgO8bag3gavrAgJ0frN4phlwdJARpE6gO1YvLEMJR0KKgoc+/Ea/A0Pp11I00xBvw==", + "license": "Apache-2.0" + }, + "node_modules/@microsoft/api-extractor": { + "version": "7.58.7", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.58.7.tgz", + "integrity": "sha512-yK6OycD46gIzLRpj6ueVUWPk1ACSpkN1LBo05gY1qPTylbWyUCanXfH7+VgkI5LJrJoRSQR5F04XuCffCXLOBw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" + "@microsoft/api-extractor-model": "7.33.8", + "@microsoft/tsdoc": "~0.16.0", + "@microsoft/tsdoc-config": "~0.18.1", + "@rushstack/node-core-library": "5.23.1", + "@rushstack/rig-package": "0.7.3", + "@rushstack/terminal": "0.24.0", + "@rushstack/ts-command-line": "5.3.9", + "diff": "~8.0.2", + "minimatch": "10.2.3", + "resolve": "~1.22.1", + "semver": "~7.7.4", + "source-map": "~0.6.1", + "typescript": "5.9.3" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "bin": { + "api-extractor": "bin/api-extractor" } }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "node_modules/@microsoft/api-extractor-model": { + "version": "7.33.8", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.33.8.tgz", + "integrity": "sha512-aIcoQggPyer3B6Ze3usz0YWC/oBwUHfRH5ETUsr+oT2BRA6SfTJl7IKPcPZkX4UR+PohowzW4uMxsvjrn8vm+w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@microsoft/tsdoc": "~0.16.0", + "@microsoft/tsdoc-config": "~0.18.1", + "@rushstack/node-core-library": "5.23.1" } }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "node_modules/@microsoft/api-extractor/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "18 || 20 || >=22" } }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", - "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "node_modules/@microsoft/api-extractor/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "18 || 20 || >=22" } }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", - "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "node_modules/@microsoft/api-extractor/node_modules/minimatch": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.3.tgz", + "integrity": "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==", "dev": true, - "license": "MIT", - "peer": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "brace-expansion": "^5.0.2" }, "engines": { - "node": ">=6.9.0" + "node": "18 || 20 || >=22" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", - "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "node_modules/@microsoft/api-extractor/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.16.0.tgz", + "integrity": "sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.18.1.tgz", + "integrity": "sha512-9brPoVdfN9k9g0dcWkFeA7IH9bbcttzDJlXvkf8b2OBzd5MueR1V2wkKBL0abn0otvmkHJC6aapBOTJDDeMCZg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "@microsoft/tsdoc": "0.16.0", + "ajv": "~8.18.0", + "jju": "~1.4.0", + "resolve": "~1.22.2" } }, - "node_modules/@babel/preset-env": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.0.tgz", - "integrity": "sha512-VmaxeGOwuDqzLl5JUkIRM1X2Qu2uKGxHEQWh+cvvbl7JuJRgKGJSfsEF/bUaxFhJl/XAyxBe7q7qSuTbKFuCyg==", + "node_modules/@microsoft/tsdoc-config/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@babel/compat-data": "^7.28.0", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.27.1", - "@babel/plugin-syntax-import-attributes": "^7.27.1", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.28.0", - "@babel/plugin-transform-async-to-generator": "^7.27.1", - "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.0", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.27.1", - "@babel/plugin-transform-classes": "^7.28.0", - "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", - "@babel/plugin-transform-dotall-regex": "^7.27.1", - "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.27.1", - "@babel/plugin-transform-export-namespace-from": "^7.27.1", - "@babel/plugin-transform-for-of": "^7.27.1", - "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.27.1", - "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", - "@babel/plugin-transform-member-expression-literals": "^7.27.1", - "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.27.1", - "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.0", - "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.27.1", - "@babel/plugin-transform-private-property-in-object": "^7.27.1", - "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.0", - "@babel/plugin-transform-regexp-modifiers": "^7.27.1", - "@babel/plugin-transform-reserved-words": "^7.27.1", - "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.27.1", - "@babel/plugin-transform-sticky-regex": "^7.27.1", - "@babel/plugin-transform-template-literals": "^7.27.1", - "@babel/plugin-transform-typeof-symbol": "^7.27.1", - "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.27.1", - "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "core-js-compat": "^3.43.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "node_modules/@microsoft/tsdoc-config/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, - "license": "MIT", - "peer": true, + "license": "MIT" + }, + "node_modules/@nextcloud/auth": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@nextcloud/auth/-/auth-2.5.3.tgz", + "integrity": "sha512-KIhWLk0BKcP4hvypE4o11YqKOPeFMfEFjRrhUUF+h7Fry+dhTBIEIxuQPVCKXMIpjTDd8791y8V6UdRZ2feKAQ==", + "license": "GPL-3.0-or-later", "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" + "@nextcloud/browser-storage": "^0.5.0", + "@nextcloud/event-bus": "^3.3.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + "engines": { + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, - "node_modules/@babel/runtime": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", - "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", - "license": "MIT", + "node_modules/@nextcloud/auth/node_modules/@nextcloud/browser-storage": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@nextcloud/browser-storage/-/browser-storage-0.5.0.tgz", + "integrity": "sha512-usYr4GlJQlK3hgZURvklqWb9ivi7sgsSuFqXrs7s4hl1LTS4enzPrnkQumm6nRsQruf0ITS+OBsK+oELEbvYPA==", + "license": "GPL-3.0-or-later", "engines": { - "node": ">=6.9.0" + "node": "^24 || ^22 || ^20" } }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "license": "MIT", - "peer": true, + "node_modules/@nextcloud/axios": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@nextcloud/axios/-/axios-2.5.1.tgz", + "integrity": "sha512-AA7BPF/rsOZWAiVxqlobGSdD67AEwjOnymZCKUIwEIBArKxYK7OQEqcILDjQwgj6G0e/Vg9Y8zTVsPZp+mlvwA==", + "license": "GPL-3.0-or-later", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@nextcloud/auth": "^2.3.0", + "@nextcloud/router": "^3.0.1", + "axios": "^1.6.8" }, "engines": { - "node": ">=6.9.0" + "node": "^20.0.0", + "npm": "^10.0.0" } }, - "node_modules/@babel/traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", - "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", - "dev": true, - "license": "MIT", - "peer": true, + "node_modules/@nextcloud/browser-storage": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@nextcloud/browser-storage/-/browser-storage-0.4.0.tgz", + "integrity": "sha512-D6XxznxCYmJ3oBCC3p0JB6GZJ2RZ9dgbB1UqtTePXrIvHUMBAeF/YkiGKYxLAVZCZb+NSNZXgAYHm/3LnIUbDg==", + "license": "GPL-3.0-or-later", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.0", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.0", - "debug": "^4.3.1" + "core-js": "3.37.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.0.0", + "npm": "^10.0.0" } }, - "node_modules/@babel/types": { - "version": "7.28.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz", - "integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==", - "license": "MIT", + "node_modules/@nextcloud/browserslist-config": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@nextcloud/browserslist-config/-/browserslist-config-3.0.1.tgz", + "integrity": "sha512-GZTxL5fsDgmFoot/qnRurjHCuHjSfOg+A6t4+P2TySXua2Q1Ex0lecZYlSnRuOR/W5BGOZ06ITTA/hbkSh1Ypg==", + "dev": true, + "license": "GPL-3.0-or-later", + "engines": { + "node": "^20.0.0", + "npm": "^10.0.0" + } + }, + "node_modules/@nextcloud/capabilities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@nextcloud/capabilities/-/capabilities-1.2.1.tgz", + "integrity": "sha512-snZ0/910zzwN6PDsIlx2Uvktr1S5x0ClhDUnfPlCj7ntNvECzuVHNY5wzby22LIkc+9ZjaDKtCwuCt2ye+9p/Q==", + "license": "GPL-3.0-or-later", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@nextcloud/initial-state": "^3.0.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, - "node_modules/@buttercup/fetch": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@buttercup/fetch/-/fetch-0.2.1.tgz", - "integrity": "sha512-sCgECOx8wiqY8NN1xN22BqqKzXYIG2AicNLlakOAI4f0WgyLVUbAigMf8CZhBtJxdudTcB1gD5lciqi44jwJvg==", - "license": "MIT", - "optionalDependencies": { - "node-fetch": "^3.3.0" + "node_modules/@nextcloud/capabilities/node_modules/@nextcloud/initial-state": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-3.0.0.tgz", + "integrity": "sha512-cV+HBdkQJGm8FxkBI5rFT/FbMNWNBvpbj6OPrg4Ae4YOOsQ15CL8InPOAw1t4XkOkQK2NEdUGQLVUz/19wXbdQ==", + "license": "GPL-3.0-or-later", + "engines": { + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, - "node_modules/@buttercup/fetch/node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "license": "MIT", - "optional": true, + "node_modules/@nextcloud/dialogs": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-6.3.2.tgz", + "integrity": "sha512-ioZ483wmKdNX1HdSJ1EG7ewTSyQAqlmbBALkhT4guZdR9JG8VIdnijX15qwKgAWITG2y36PWoi9Rimb3dDf+7A==", "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" + "@mdi/js": "^7.4.47", + "@nextcloud/auth": "^2.5.1", + "@nextcloud/axios": "^2.5.1", + "@nextcloud/browser-storage": "^0.4.0", + "@nextcloud/event-bus": "^3.3.2", + "@nextcloud/files": "^3.10.2", + "@nextcloud/initial-state": "^2.2.0", + "@nextcloud/l10n": "^3.3.0", + "@nextcloud/router": "^3.0.1", + "@nextcloud/sharing": "^0.2.4", + "@nextcloud/typings": "^1.9.1", + "@types/toastify-js": "^1.12.4", + "@vueuse/core": "^11.3.0", + "cancelable-promise": "^4.3.1", + "p-queue": "^8.1.0", + "toastify-js": "^1.12.0", + "vue-frag": "^1.4.3", + "webdav": "^5.8.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0", + "npm": "^10.5.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" + "peerDependencies": { + "@nextcloud/vue": "^8.24.0", + "vue": "^2.7.16" } }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "node_modules/@nextcloud/eslint-config": { + "version": "9.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@nextcloud/eslint-config/-/eslint-config-9.0.0-rc.9.tgz", + "integrity": "sha512-YEz7bWv8mXz1QzzTd9qVn9koFn3Qmz97KLBQ2ssCFHVLthaxbVPYtwQOKiQagg2EOCUc+NyP04+Pr6BOzmMEkg==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "peer": true, + "license": "AGPL-3.0-or-later", + "dependencies": { + "@eslint/js": "^10.0.1", + "@eslint/json": "^1.2.0", + "@stylistic/eslint-plugin": "^5.10.0", + "eslint-config-flat-gitignore": "^2.3.0", + "eslint-plugin-antfu": "^3.2.2", + "eslint-plugin-jsdoc": "^62.9.0", + "eslint-plugin-perfectionist": "^5.8.0", + "eslint-plugin-vue": "^10.8.0", + "fast-xml-parser": "^5.5.10", + "globals": "^17.4.0", + "semver": "^7.7.4", + "sort-package-json": "^3.6.1", + "typescript-eslint": "^8.58.0" + }, "engines": { - "node": ">=18" + "node": "^20.19 || ^22.13 || ^24" }, "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" + "eslint": ">=10" } }, - "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "node_modules/@nextcloud/eslint-config/node_modules/fast-xml-parser": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.2.tgz", + "integrity": "sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w==", "dev": true, "funding": [ { "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "url": "https://github.com/sponsors/NaturalIntelligence" } ], "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" + "dependencies": { + "@nodable/entities": "^2.1.0", + "fast-xml-builder": "^1.1.5", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.2.3" + }, + "bin": { + "fxparser": "src/cli/cli.js" } }, - "node_modules/@csstools/media-query-list-parser": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz", - "integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==", + "node_modules/@nextcloud/eslint-config/node_modules/globals": { + "version": "17.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.5.0.tgz", + "integrity": "sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", - "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=14.17.0" - } - }, - "node_modules/@dual-bundle/import-meta-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", - "integrity": "sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg==", - "dev": true, - "license": "MIT", - "peer": true, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.41.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", - "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", + "node_modules/@nextcloud/eslint-config/node_modules/strnum": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.3.tgz", + "integrity": "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==", "dev": true, - "license": "MIT", - "peer": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/@nextcloud/event-bus": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@nextcloud/event-bus/-/event-bus-3.3.3.tgz", + "integrity": "sha512-zIfvKmUGkXpVzRKoXrcO9hkoiKDm65fqNxy/XIbIxrQhZByPq3gDkjBpnu3V5Gs8JdYwa73R8DjzV9oH8HYhIg==", "dependencies": { - "comment-parser": "1.4.1", - "esquery": "^1.5.0", - "jsdoc-type-pratt-parser": "~4.0.0" + "@types/semver": "^7.7.0", + "semver": "^7.7.2" }, "engines": { - "node": ">=16" + "node": "^20 || ^22 || ^24" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", - "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", - "dev": true, - "license": "MIT", - "peer": true, + "node_modules/@nextcloud/files": { + "version": "3.12.2", + "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-3.12.2.tgz", + "integrity": "sha512-vBo8tf3Xh6efiF8CrEo3pKj9AtvAF6RdDGO1XKL65IxV8+UUd9Uxl2lUExHlzoDRRczCqfGfaWfRRaFhYqce5Q==", + "license": "AGPL-3.0-or-later", "dependencies": { - "eslint-visitor-keys": "^3.4.3" + "@nextcloud/auth": "^2.5.3", + "@nextcloud/capabilities": "^1.2.1", + "@nextcloud/l10n": "^3.4.1", + "@nextcloud/logger": "^3.0.3", + "@nextcloud/paths": "^3.0.0", + "@nextcloud/router": "^3.1.0", + "@nextcloud/sharing": "^0.3.0", + "cancelable-promise": "^4.3.1", + "is-svg": "^6.1.0", + "typescript-event-target": "^1.1.1", + "webdav": "^5.8.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "peer": true, + "node_modules/@nextcloud/files/node_modules/@nextcloud/initial-state": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-3.0.0.tgz", + "integrity": "sha512-cV+HBdkQJGm8FxkBI5rFT/FbMNWNBvpbj6OPrg4Ae4YOOsQ15CL8InPOAw1t4XkOkQK2NEdUGQLVUz/19wXbdQ==", + "license": "GPL-3.0-or-later", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "license": "MIT", - "peer": true, + "node_modules/@nextcloud/files/node_modules/@nextcloud/paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nextcloud/paths/-/paths-3.0.0.tgz", + "integrity": "sha512-+sTfTkIbVUa2Ue3bkz3R7F1mhddvHPOWUxkSNg7Q5dAsimVFBaTRgiBAJmsAag3JPsxyuS8kUgeb0zdEssRdTA==", + "license": "GPL-3.0-or-later", "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "license": "MIT", - "peer": true, + "node_modules/@nextcloud/files/node_modules/@nextcloud/sharing": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@nextcloud/sharing/-/sharing-0.3.0.tgz", + "integrity": "sha512-kV7qeUZvd1fTKeFyH+W5Qq5rNOqG9rLATZM3U9MBxWXHJs3OxMqYQb8UQ3NYONzsX3zDGJmdQECIGHm1ei2sCA==", + "license": "GPL-3.0-or-later", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@nextcloud/initial-state": "^3.0.0", + "is-svg": "^6.1.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "optionalDependencies": { + "@nextcloud/files": "^3.12.0" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node_modules/@nextcloud/initial-state": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-2.2.0.tgz", + "integrity": "sha512-cDW98L5KGGgpS8pzd+05304/p80cyu8U2xSDQGa+kGPTpUFmCbv2qnO5WrwwGTauyjYijCal2bmw82VddSH+Pg==", + "license": "GPL-3.0-or-later", + "engines": { + "node": "^20.0.0", + "npm": "^10.0.0" } }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "peer": true, + "node_modules/@nextcloud/l10n": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-3.4.1.tgz", + "integrity": "sha512-aTFinTcKiK2gEXwLgutXekpZZ8/v/4QiC8C3QCLH5m0o+WtxsBC+fqV142ebC/rfDnzCLhY4ZtswSu8bFbZocg==", + "license": "GPL-3.0-or-later", "dependencies": { - "brace-expansion": "^1.1.7" + "@nextcloud/router": "^3.0.1", + "@nextcloud/typings": "^1.9.1", + "@types/escape-html": "^1.0.4", + "dompurify": "^3.2.6", + "escape-html": "^1.0.3" }, "engines": { - "node": "*" + "node": "^20 || ^22 || ^24" } }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, - "license": "MIT", - "peer": true, + "node_modules/@nextcloud/logger": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@nextcloud/logger/-/logger-3.0.3.tgz", + "integrity": "sha512-TcbVRL4/O5ffI1RXFmQAFD3gwwT15AAdr1770x+RNqVvfBdoGVyhzOwCIyA5Vfc3fA1iJXFa+rE6buJZSoqlcw==", + "license": "GPL-3.0-or-later", + "dependencies": { + "@nextcloud/auth": "^2.5.3" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, - "node_modules/@file-type/xml": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@file-type/xml/-/xml-0.4.3.tgz", - "integrity": "sha512-pGRmkHf+NofNy/52r06HOTsEwdNnBsFEhN6U95s33P+ezuoxZEyBTV9lOB1/Zr0So6/9vDVfWZXLpgd0fy8cOQ==", - "license": "MIT", + "node_modules/@nextcloud/moment": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@nextcloud/moment/-/moment-1.3.5.tgz", + "integrity": "sha512-sQjQ/D40sdedtq4ywuANSxqG0VhIB/i+QtZ6Voz3nyZWhkyyqGxdj9rQu9AyEvas3/Jlspdom5chc+a8jOmHxQ==", + "license": "GPL-3.0-or-later", "dependencies": { - "sax": "^1.4.1", - "strtok3": "^10.2.2" + "@nextcloud/l10n": "^3.4.0", + "moment": "^2.30.1" + }, + "engines": { + "node": "^20.0.0", + "npm": "^10.0.0" } }, - "node_modules/@floating-ui/core": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.2.tgz", - "integrity": "sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==", - "license": "MIT", - "dependencies": { - "@floating-ui/utils": "^0.2.10" + "node_modules/@nextcloud/paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@nextcloud/paths/-/paths-2.2.1.tgz", + "integrity": "sha512-M3ShLjrxR7B48eKThLMoqbxTqTKyQXcwf9TgeXQGbCIhiHoXU6as5j8l5qNv/uZlANokVdowpuWHBi3b2+YNNA==", + "license": "GPL-3.0-or-later", + "engines": { + "node": "^20.0.0", + "npm": "^10.0.0" } }, - "node_modules/@floating-ui/dom": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.2.tgz", - "integrity": "sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==", - "license": "MIT", + "node_modules/@nextcloud/router": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-3.1.0.tgz", + "integrity": "sha512-e4dkIaxRSwdZJlZFpn9x03QgBn/Sa2hN1hp/BA7+AbzykmSAlKuWfdmX8j/8ewrLpQwYmZR23IZO9XwpJXq2Uw==", + "license": "GPL-3.0-or-later", "dependencies": { - "@floating-ui/core": "^1.7.2", - "@floating-ui/utils": "^0.2.10" - } - }, - "node_modules/@floating-ui/utils": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", - "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", - "license": "MIT" - }, - "node_modules/@fortawesome/fontawesome-free": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz", - "integrity": "sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==", + "@nextcloud/typings": "^1.10.0" + }, "engines": { - "node": ">=6" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, + "node_modules/@nextcloud/sharing": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@nextcloud/sharing/-/sharing-0.2.5.tgz", + "integrity": "sha512-B3K5Dq9b5dexDA5n3AAuCF69Huwhrpw0J72fsVXV4KpPdImjhVPlExAv5o70AoXa+OqN4Rwn6gqJw+3ED892zg==", + "license": "GPL-3.0-or-later", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@nextcloud/initial-state": "^2.2.0" }, "engines": { - "node": ">=10.10.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/@nextcloud/stylelint-config": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@nextcloud/stylelint-config/-/stylelint-config-3.1.0.tgz", + "integrity": "sha512-ZKr/AeqfcqIziJAxnN4K0ldoGz8zWj8pUTov4eloqfaCgvJxcQkt2ldHJfxbutNq8uFkbvRYagkufaYxjC4FlQ==", "dev": true, - "license": "MIT", - "peer": true, + "license": "AGPL-3.0-or-later", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "stylelint-use-logical": "^2.1.2" + }, + "engines": { + "node": "^20.0.0", + "npm": "^10.0.0" + }, + "peerDependencies": { + "stylelint": "^16.13.2", + "stylelint-config-recommended-scss": "^15.0.1", + "stylelint-config-recommended-vue": "^1.5.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "peer": true, + "node_modules/@nextcloud/timezones": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@nextcloud/timezones/-/timezones-0.2.0.tgz", + "integrity": "sha512-1mwQ+asTFOgv9rxPoAMEbDF8JfnenIa2EGNS+8MATCyi6WXxYh0Lhkaq1d3l2+xNbUPHgMnk4cRYsvIo319lkA==", + "license": "AGPL-3.0-or-later", "dependencies": { - "brace-expansion": "^1.1.7" + "ical.js": "^2.1.0" }, "engines": { - "node": "*" + "node": "^20 || ^22" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=12.22" + "node_modules/@nextcloud/typings": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@nextcloud/typings/-/typings-1.10.0.tgz", + "integrity": "sha512-SMC42rDjOH3SspPTLMZRv76ZliHpj2JJkF8pGLP8l1QrVTZxE47Qz5qeKmbj2VL+dRv2e/NgixlAFmzVnxkhqg==", + "license": "GPL-3.0-or-later", + "dependencies": { + "@types/jquery": "3.5.16" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "engines": { + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "node_modules/@nextcloud/vite-config": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@nextcloud/vite-config/-/vite-config-1.7.2.tgz", + "integrity": "sha512-5KILNBVEComCyFw6OI2QKvAT5bTMo3Z0o/YN+UpAm8LC3CnuLplRl5Z4UPQZMKdQeMHZ2WXmqL+biSfM7bweJw==", "dev": true, - "license": "BSD-3-Clause", - "peer": true + "license": "AGPL-3.0-or-later", + "dependencies": { + "@rollup/plugin-replace": "^6.0.2", + "@vitejs/plugin-vue2": "^2.3.4", + "browserslist-to-esbuild": "^2.1.1", + "magic-string": "^0.30.19", + "rollup-plugin-corejs": "^1.0.1", + "rollup-plugin-esbuild-minify": "^1.3.0", + "rollup-plugin-license": "^3.6.0", + "rollup-plugin-node-externals": "^8.1.1", + "spdx-expression-parse": "^4.0.0", + "vite-plugin-css-injected-by-js": "^3.5.2", + "vite-plugin-dts": "^4.5.4", + "vite-plugin-node-polyfills": "^0.24.0" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || ^24.0.0", + "npm": "^10.5.1" + }, + "peerDependencies": { + "browserslist": ">=4.0", + "sass": ">=1.60", + "vite": "^7.1.10" + } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", - "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", - "license": "MIT", - "peer": true, + "node_modules/@nextcloud/vue": { + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-8.28.0.tgz", + "integrity": "sha512-m0Ei6LpySq5OBb2zNqOx5vasDsmmiDTYtCoWb20ZBCT3+uk3D2m02US9g+1dS4v/Gb4BcwFLYm5mwlRH9zNERw==", + "license": "AGPL-3.0-or-later", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@floating-ui/dom": "^1.1.0", + "@linusborg/vue-simple-portal": "^0.1.5", + "@nextcloud/auth": "^2.4.0", + "@nextcloud/axios": "^2.5.0", + "@nextcloud/browser-storage": "^0.4.0", + "@nextcloud/capabilities": "^1.2.0", + "@nextcloud/event-bus": "^3.3.2", + "@nextcloud/initial-state": "^2.2.0", + "@nextcloud/l10n": "^3.4.0", + "@nextcloud/logger": "^3.0.2", + "@nextcloud/router": "^3.0.1", + "@nextcloud/sharing": "^0.2.3", + "@nextcloud/timezones": "^0.2.0", + "@nextcloud/vue-select": "^3.25.1", + "@vueuse/components": "^11.0.0", + "@vueuse/core": "^11.0.0", + "blurhash": "^2.0.5", + "clone": "^2.1.2", + "debounce": "^2.2.0", + "dompurify": "^3.2.4", + "emoji-mart-vue-fast": "^15.0.4", + "escape-html": "^1.0.3", + "floating-vue": "^1.0.0-beta.19", + "focus-trap": "^7.4.3", + "linkify-string": "^4.0.0", + "md5": "^2.3.0", + "p-queue": "^8.1.0", + "rehype-external-links": "^3.0.0", + "rehype-highlight": "^7.0.2", + "rehype-react": "^7.1.2", + "remark-breaks": "^4.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "remark-unlink-protocols": "^1.0.0", + "splitpanes": "^2.4.1", + "string-length": "^5.0.1", + "striptags": "^3.2.0", + "tabbable": "^6.2.0", + "tributejs": "^5.1.3", + "unified": "^11.0.1", + "unist-builder": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vue": "^2.7.16", + "vue-color": "^2.8.1", + "vue-frag": "^1.4.3", + "vue-router": "^3.6.5", + "vue2-datepicker": "^3.11.0" + }, + "engines": { + "node": "^20.0.0", + "npm": "^10.0.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@nextcloud/vue-select": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/@nextcloud/vue-select/-/vue-select-3.25.1.tgz", + "integrity": "sha512-jqCi4G+Q0H6+Hm8wSN3vRX2+eXG2jXR2bwBX/sErVEsH5UaxT4Nb7KqgdeIjVfeF7ccIdRqpmIb4Pkf0lao67w==", "license": "MIT", - "peer": true, "engines": { - "node": ">=6.0.0" + "node": "^20.0.0" + }, + "peerDependencies": { + "vue": "2.x" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.10.tgz", - "integrity": "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==", + "node_modules/@nodable/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", - "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", - "license": "MIT", - "peer": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.29", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", - "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "license": "MIT", "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "engines": { + "node": ">= 8" } }, - "node_modules/@jsonjoy.com/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "peer": true, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, - "peerDependencies": { - "tslib": "2" + "engines": { + "node": ">= 8" } }, - "node_modules/@jsonjoy.com/json-pack": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.2.0.tgz", - "integrity": "sha512-io1zEbbYcElht3tdlqEOFxZ0dMTYrHz9iMf0gqn1pPjZFTCgM5R4R5IMA20Chb2UPYYsxjzs8CgZ7Nb5n2K2rA==", + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", "dev": true, - "license": "Apache-2.0", - "peer": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, "dependencies": { - "@jsonjoy.com/base64": "^1.1.1", - "@jsonjoy.com/util": "^1.1.2", - "hyperdyperid": "^1.2.0", - "thingies": "^1.20.0" + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" }, "engines": { - "node": ">=10.0" + "node": ">= 10.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" + "type": "opencollective", + "url": "https://opencollective.com/parcel" }, - "peerDependencies": { - "tslib": "2" + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" } }, - "node_modules/@jsonjoy.com/util": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.6.0.tgz", - "integrity": "sha512-sw/RMbehRhN68WRtcKCpQOPfnH6lLP4GJfqzi3iYej8tnzpZUDr6UkZYJjcjjC0FWEJOJbyM3PTIwxucUmDG2A==", + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "peer": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10.0" + "node": ">= 10.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@keyv/serialize": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.0.3.tgz", - "integrity": "sha512-qnEovoOp5Np2JDGonIDL6Ayihw0RhnRh6vxPuHo4RDn1UOzwEo4AeIfpL6UGIrsceWrCMiVPgwRjbHu4vYFc3g==", + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "buffer": "^6.0.3" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "node_modules/@raruto/leaflet-elevation": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@raruto/leaflet-elevation/-/leaflet-elevation-2.5.2.tgz", + "integrity": "sha512-bXWxDe72MeD5eBn6u06mF9agf2PFUg81OvT6QBQRacg+fkI4UHYL9eLcbvFo5uHltf7bN/M6f+FWsHMfgc9+QA==", + "license": "GPL-3.0", + "peerDependencies": { + "@tmcw/togeojson": "5.6.2", + "d3": "7.8.4", + "leaflet": "^1.7.0", + "leaflet-i18n": "^0.3.1" + } + }, + "node_modules/@rollup/plugin-inject": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz", + "integrity": "sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==", "dev": true, "license": "MIT", - "peer": true - }, - "node_modules/@linusborg/vue-simple-portal": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@linusborg/vue-simple-portal/-/vue-simple-portal-0.1.5.tgz", - "integrity": "sha512-dq+oubEVW4UabBoQxmH97GiDa+F6sTomw4KcXFHnXEpw69rdkXFCxo1WzwuvWjoLiUVYJTyN1dtlUvTa50VcXg==", - "license": "Apache-2.0", "dependencies": { - "nanoid": "^3.1.20" + "@rollup/pluginutils": "^5.0.1", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" }, "peerDependencies": { - "vue": "^2.6.6" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/@mapbox/corslite": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@mapbox/corslite/-/corslite-0.0.7.tgz", - "integrity": "sha512-w/uS474VFjmqQ7fFWIMZINQM1BAQxDLuoJaZZIPES1BmeYpCtlh9MtbFxKGGDAsfvut8/HircIsVvEYRjQ+iMg==", - "license": "BSD" - }, - "node_modules/@mapbox/geojson-rewind": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", - "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", - "license": "ISC", + "node_modules/@rollup/plugin-replace": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.3.tgz", + "integrity": "sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==", + "dev": true, + "license": "MIT", "dependencies": { - "get-stream": "^6.0.1", - "minimist": "^1.2.6" + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" }, - "bin": { - "geojson-rewind": "geojson-rewind" + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/@mapbox/hast-util-table-cell-style": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@mapbox/hast-util-table-cell-style/-/hast-util-table-cell-style-0.2.1.tgz", - "integrity": "sha512-LyQz4XJIdCdY/+temIhD/Ed0x/p4GAOUycpFSEK2Ads1CPKZy6b7V/2ROEtQiLLQ8soIs0xe/QAoR6kwpyW/yw==", - "license": "BSD-2-Clause", + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "license": "MIT", "dependencies": { - "unist-util-visit": "^1.4.1" + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@mapbox/hast-util-table-cell-style/node_modules/unist-util-is": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz", - "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==", - "license": "MIT" + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz", + "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@mapbox/hast-util-table-cell-style/node_modules/unist-util-visit": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz", - "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz", + "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "unist-util-visit-parents": "^2.0.0" - } + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@mapbox/hast-util-table-cell-style/node_modules/unist-util-visit-parents": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz", - "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz", + "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "unist-util-is": "^3.0.0" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@mapbox/jsonlint-lines-primitives": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", - "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", - "engines": { - "node": ">= 0.6" - } + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz", + "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@mapbox/mapbox-gl-supported": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-3.0.0.tgz", - "integrity": "sha512-2XghOwu16ZwPJLOFVuIOaLbN0iKMn867evzXFyf0P22dqugezfJwLmdanAgU25ITvz1TvOfVP4jsDImlDJzcWg==", - "license": "BSD-3-Clause" + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz", + "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@mapbox/point-geometry": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-1.1.0.tgz", - "integrity": "sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ==", - "license": "ISC" + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz", + "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@mapbox/polyline": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@mapbox/polyline/-/polyline-0.2.0.tgz", - "integrity": "sha512-GCddO0iw6AzOQqZgBmjEQI9Pgo40/yRgkTkikGctE01kNBN0ThWYuAnTD+hRWrAWMV6QJ0rNm4m8DAsaAXE7Pg==", - "bin": { - "polyline": "bin/polyline.bin.js" - }, - "engines": { - "node": "*" - } + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz", + "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@mapbox/tiny-sdf": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.7.tgz", - "integrity": "sha512-25gQLQMcpivjOSA40g3gO6qgiFPDpWRoMfd+G/GoppPIeP6JDaMMkMrEJnMZhKyyS6iKwVt5YKu02vCUyJM3Ug==", - "license": "BSD-2-Clause" + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz", + "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@mapbox/unitbezier": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", - "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", - "license": "BSD-2-Clause" + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz", + "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@mapbox/vector-tile": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-2.0.4.tgz", - "integrity": "sha512-AkOLcbgGTdXScosBWwmmD7cDlvOjkg/DetGva26pIRiZPdeJYjYKarIlb4uxVzi6bwHO6EWH82eZ5Nuv4T5DUg==", - "license": "BSD-3-Clause", - "dependencies": { - "@mapbox/point-geometry": "~1.1.0", - "@types/geojson": "^7946.0.16", - "pbf": "^4.0.1" - } + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz", + "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@mapbox/whoots-js": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", - "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", - "license": "ISC", - "engines": { - "node": ">=6.0.0" - } + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz", + "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@maplibre/geojson-vt": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-5.0.4.tgz", - "integrity": "sha512-KGg9sma45S+stfH9vPCJk1J0lSDLWZgCT9Y8u8qWZJyjFlP8MNP1WGTxIMYJZjDvVT3PDn05kN1C95Sut1HpgQ==", - "license": "ISC" + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz", + "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@maplibre/maplibre-gl-leaflet": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-leaflet/-/maplibre-gl-leaflet-0.1.2.tgz", - "integrity": "sha512-3BzJlaqtWxXZdK+dTjuQ/0ayOwpcT0JPNaGgnbApm5itPBENotMcZoJhRdLKljmTRyXM9/v2+eOyv/xWYVd78A==", - "peerDependencies": { - "@types/leaflet": "^1.9.0", - "leaflet": "^1.9.3", - "maplibre-gl": "^2.4.0 || ^3.3.1 || ^4.3.2 || ^5.0.0" - } + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz", + "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@maplibre/maplibre-gl-style-spec": { - "version": "24.4.1", - "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.4.1.tgz", - "integrity": "sha512-UKhA4qv1h30XT768ccSv5NjNCX+dgfoq2qlLVmKejspPcSQTYD4SrVucgqegmYcKcmwf06wcNAa/kRd0NHWbUg==", - "license": "ISC", - "dependencies": { - "@mapbox/jsonlint-lines-primitives": "~2.0.2", - "@mapbox/unitbezier": "^0.0.1", - "json-stringify-pretty-compact": "^4.0.0", - "minimist": "^1.2.8", - "quickselect": "^3.0.0", - "rw": "^1.3.3", - "tinyqueue": "^3.0.0" - }, - "bin": { - "gl-style-format": "dist/gl-style-format.mjs", - "gl-style-migrate": "dist/gl-style-migrate.mjs", - "gl-style-validate": "dist/gl-style-validate.mjs" - } - }, - "node_modules/@maplibre/mlt": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.1.6.tgz", - "integrity": "sha512-rgtY3x65lrrfXycLf6/T22ZnjTg5WgIOsptOIoCaMZy4O4UAKTyZlYY0h6v8le721pTptF94U65yMDQkug+URw==", - "license": "(MIT OR Apache-2.0)", - "dependencies": { - "@mapbox/point-geometry": "^1.1.0" - } - }, - "node_modules/@maplibre/vt-pbf": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@maplibre/vt-pbf/-/vt-pbf-4.2.1.tgz", - "integrity": "sha512-IxZBGq/+9cqf2qdWlFuQ+ZfoMhWpxDUGQZ/poPHOJBvwMUT1GuxLo6HgYTou+xxtsOsjfbcjI8PZaPCtmt97rA==", + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz", + "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==", + "cpu": [ + "ppc64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@mapbox/point-geometry": "^1.1.0", - "@mapbox/vector-tile": "^2.0.4", - "@maplibre/geojson-vt": "^5.0.4", - "@types/geojson": "^7946.0.16", - "@types/supercluster": "^7.1.3", - "pbf": "^4.0.1", - "supercluster": "^8.0.1" - } - }, - "node_modules/@mdi/js": { - "version": "7.4.47", - "resolved": "https://registry.npmjs.org/@mdi/js/-/js-7.4.47.tgz", - "integrity": "sha512-KPnNOtm5i2pMabqZxpUz7iQf+mfrYZyKCZ8QNz85czgEt7cuHcGorWfdzUMWYA0SD+a6Hn4FmJ+YhzzzjkTZrQ==", - "license": "Apache-2.0" - }, - "node_modules/@mdi/svg": { - "version": "7.4.47", - "resolved": "https://registry.npmjs.org/@mdi/svg/-/svg-7.4.47.tgz", - "integrity": "sha512-WQ2gDll12T9WD34fdRFgQVgO8bag3gavrAgJ0frN4phlwdJARpE6gO1YvLEMJR0KKgoc+/Ea/A0Pp11I00xBvw==", - "license": "Apache-2.0" - }, - "node_modules/@nextcloud/auth": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@nextcloud/auth/-/auth-2.5.3.tgz", - "integrity": "sha512-KIhWLk0BKcP4hvypE4o11YqKOPeFMfEFjRrhUUF+h7Fry+dhTBIEIxuQPVCKXMIpjTDd8791y8V6UdRZ2feKAQ==", - "license": "GPL-3.0-or-later", - "dependencies": { - "@nextcloud/browser-storage": "^0.5.0", - "@nextcloud/event-bus": "^3.3.2" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - } - }, - "node_modules/@nextcloud/auth/node_modules/@nextcloud/browser-storage": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@nextcloud/browser-storage/-/browser-storage-0.5.0.tgz", - "integrity": "sha512-usYr4GlJQlK3hgZURvklqWb9ivi7sgsSuFqXrs7s4hl1LTS4enzPrnkQumm6nRsQruf0ITS+OBsK+oELEbvYPA==", - "license": "GPL-3.0-or-later", - "engines": { - "node": "^24 || ^22 || ^20" - } - }, - "node_modules/@nextcloud/axios": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@nextcloud/axios/-/axios-2.5.1.tgz", - "integrity": "sha512-AA7BPF/rsOZWAiVxqlobGSdD67AEwjOnymZCKUIwEIBArKxYK7OQEqcILDjQwgj6G0e/Vg9Y8zTVsPZp+mlvwA==", - "license": "GPL-3.0-or-later", - "dependencies": { - "@nextcloud/auth": "^2.3.0", - "@nextcloud/router": "^3.0.1", - "axios": "^1.6.8" - }, - "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@nextcloud/babel-config": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@nextcloud/babel-config/-/babel-config-1.3.0.tgz", - "integrity": "sha512-qk4mBJahzp2mkiizU9RbeABa6JhqSwR43SXptNQhM3kpxAuP2OAQQhomYnxog/XfFcYExZzOkgRBPlcLEoik0w==", + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz", + "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==", + "cpu": [ + "riscv64" + ], "dev": true, - "engines": { - "node": "^20 || ^22 || ^24" - }, - "peerDependencies": { - "@babel/core": "^7.27.4", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/preset-env": "^7.27.2" - } - }, - "node_modules/@nextcloud/browser-storage": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@nextcloud/browser-storage/-/browser-storage-0.4.0.tgz", - "integrity": "sha512-D6XxznxCYmJ3oBCC3p0JB6GZJ2RZ9dgbB1UqtTePXrIvHUMBAeF/YkiGKYxLAVZCZb+NSNZXgAYHm/3LnIUbDg==", - "license": "GPL-3.0-or-later", - "dependencies": { - "core-js": "3.37.0" - }, - "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@nextcloud/browserslist-config": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@nextcloud/browserslist-config/-/browserslist-config-3.0.1.tgz", - "integrity": "sha512-GZTxL5fsDgmFoot/qnRurjHCuHjSfOg+A6t4+P2TySXua2Q1Ex0lecZYlSnRuOR/W5BGOZ06ITTA/hbkSh1Ypg==", + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz", + "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==", + "cpu": [ + "riscv64" + ], "dev": true, - "license": "GPL-3.0-or-later", - "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" - } - }, - "node_modules/@nextcloud/capabilities": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@nextcloud/capabilities/-/capabilities-1.2.1.tgz", - "integrity": "sha512-snZ0/910zzwN6PDsIlx2Uvktr1S5x0ClhDUnfPlCj7ntNvECzuVHNY5wzby22LIkc+9ZjaDKtCwuCt2ye+9p/Q==", - "license": "GPL-3.0-or-later", - "dependencies": { - "@nextcloud/initial-state": "^3.0.0" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - } - }, - "node_modules/@nextcloud/capabilities/node_modules/@nextcloud/initial-state": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-3.0.0.tgz", - "integrity": "sha512-cV+HBdkQJGm8FxkBI5rFT/FbMNWNBvpbj6OPrg4Ae4YOOsQ15CL8InPOAw1t4XkOkQK2NEdUGQLVUz/19wXbdQ==", - "license": "GPL-3.0-or-later", - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - } - }, - "node_modules/@nextcloud/dialogs": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-6.3.2.tgz", - "integrity": "sha512-ioZ483wmKdNX1HdSJ1EG7ewTSyQAqlmbBALkhT4guZdR9JG8VIdnijX15qwKgAWITG2y36PWoi9Rimb3dDf+7A==", - "dependencies": { - "@mdi/js": "^7.4.47", - "@nextcloud/auth": "^2.5.1", - "@nextcloud/axios": "^2.5.1", - "@nextcloud/browser-storage": "^0.4.0", - "@nextcloud/event-bus": "^3.3.2", - "@nextcloud/files": "^3.10.2", - "@nextcloud/initial-state": "^2.2.0", - "@nextcloud/l10n": "^3.3.0", - "@nextcloud/router": "^3.0.1", - "@nextcloud/sharing": "^0.2.4", - "@nextcloud/typings": "^1.9.1", - "@types/toastify-js": "^1.12.4", - "@vueuse/core": "^11.3.0", - "cancelable-promise": "^4.3.1", - "p-queue": "^8.1.0", - "toastify-js": "^1.12.0", - "vue-frag": "^1.4.3", - "webdav": "^5.8.0" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0", - "npm": "^10.5.1" - }, - "peerDependencies": { - "@nextcloud/vue": "^8.24.0", - "vue": "^2.7.16" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@nextcloud/eslint-config": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/@nextcloud/eslint-config/-/eslint-config-8.4.2.tgz", - "integrity": "sha512-zsDcBxvp2Vr/BgasK/vNYJ84LOXjl4RseJPrcp93zcnaB2WnygV50Sd0nQ5JN0ngTyPjiIlGd92MMzrMTofjRA==", - "dev": true, - "license": "AGPL-3.0-or-later", - "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.26.9", - "@babel/eslint-parser": "^7.16.5", - "@nextcloud/eslint-plugin": "^2.2.1", - "@vue/eslint-config-typescript": "^13.0.0", - "eslint": "^8.27.0", - "eslint-config-standard": "^17.1.0", - "eslint-import-resolver-exports": "^1.0.0-beta.5", - "eslint-import-resolver-typescript": "^3.8.0", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-jsdoc": "^46.2.6", - "eslint-plugin-n": "^16.0.0", - "eslint-plugin-promise": "^6.6.0", - "eslint-plugin-vue": "^9.7.0", - "typescript": "^5.0.2" - } - }, - "node_modules/@nextcloud/eslint-plugin": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@nextcloud/eslint-plugin/-/eslint-plugin-2.2.1.tgz", - "integrity": "sha512-RX+0FxpL1h2EzjNLeW0VSGTkbyWIq7WgV7QAjtyUmDbSGwf1ds9Zy5OcRkgXRHRIu/W0gB0DhS2iz9qXHphCzA==", + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz", + "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==", + "cpu": [ + "s390x" + ], "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "fast-xml-parser": "^4.2.5", - "requireindex": "^1.2.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@nextcloud/eslint-plugin/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", + "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@nextcloud/event-bus": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@nextcloud/event-bus/-/event-bus-3.3.3.tgz", - "integrity": "sha512-zIfvKmUGkXpVzRKoXrcO9hkoiKDm65fqNxy/XIbIxrQhZByPq3gDkjBpnu3V5Gs8JdYwa73R8DjzV9oH8HYhIg==", - "dependencies": { - "@types/semver": "^7.7.0", - "semver": "^7.7.2" - }, - "engines": { - "node": "^20 || ^22 || ^24" - } - }, - "node_modules/@nextcloud/event-bus/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@nextcloud/files": { - "version": "3.12.2", - "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-3.12.2.tgz", - "integrity": "sha512-vBo8tf3Xh6efiF8CrEo3pKj9AtvAF6RdDGO1XKL65IxV8+UUd9Uxl2lUExHlzoDRRczCqfGfaWfRRaFhYqce5Q==", - "license": "AGPL-3.0-or-later", - "dependencies": { - "@nextcloud/auth": "^2.5.3", - "@nextcloud/capabilities": "^1.2.1", - "@nextcloud/l10n": "^3.4.1", - "@nextcloud/logger": "^3.0.3", - "@nextcloud/paths": "^3.0.0", - "@nextcloud/router": "^3.1.0", - "@nextcloud/sharing": "^0.3.0", - "cancelable-promise": "^4.3.1", - "is-svg": "^6.1.0", - "typescript-event-target": "^1.1.1", - "webdav": "^5.8.0" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - } - }, - "node_modules/@nextcloud/files/node_modules/@nextcloud/initial-state": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-3.0.0.tgz", - "integrity": "sha512-cV+HBdkQJGm8FxkBI5rFT/FbMNWNBvpbj6OPrg4Ae4YOOsQ15CL8InPOAw1t4XkOkQK2NEdUGQLVUz/19wXbdQ==", - "license": "GPL-3.0-or-later", - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - } - }, - "node_modules/@nextcloud/files/node_modules/@nextcloud/paths": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@nextcloud/paths/-/paths-3.0.0.tgz", - "integrity": "sha512-+sTfTkIbVUa2Ue3bkz3R7F1mhddvHPOWUxkSNg7Q5dAsimVFBaTRgiBAJmsAag3JPsxyuS8kUgeb0zdEssRdTA==", - "license": "GPL-3.0-or-later", - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - } - }, - "node_modules/@nextcloud/files/node_modules/@nextcloud/sharing": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@nextcloud/sharing/-/sharing-0.3.0.tgz", - "integrity": "sha512-kV7qeUZvd1fTKeFyH+W5Qq5rNOqG9rLATZM3U9MBxWXHJs3OxMqYQb8UQ3NYONzsX3zDGJmdQECIGHm1ei2sCA==", - "license": "GPL-3.0-or-later", - "dependencies": { - "@nextcloud/initial-state": "^3.0.0", - "is-svg": "^6.1.0" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - }, - "optionalDependencies": { - "@nextcloud/files": "^3.12.0" - } - }, - "node_modules/@nextcloud/initial-state": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@nextcloud/initial-state/-/initial-state-2.2.0.tgz", - "integrity": "sha512-cDW98L5KGGgpS8pzd+05304/p80cyu8U2xSDQGa+kGPTpUFmCbv2qnO5WrwwGTauyjYijCal2bmw82VddSH+Pg==", - "license": "GPL-3.0-or-later", - "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@nextcloud/l10n": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-3.4.1.tgz", - "integrity": "sha512-aTFinTcKiK2gEXwLgutXekpZZ8/v/4QiC8C3QCLH5m0o+WtxsBC+fqV142ebC/rfDnzCLhY4ZtswSu8bFbZocg==", - "license": "GPL-3.0-or-later", - "dependencies": { - "@nextcloud/router": "^3.0.1", - "@nextcloud/typings": "^1.9.1", - "@types/escape-html": "^1.0.4", - "dompurify": "^3.2.6", - "escape-html": "^1.0.3" - }, - "engines": { - "node": "^20 || ^22 || ^24" - } + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz", + "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@nextcloud/logger": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@nextcloud/logger/-/logger-3.0.3.tgz", - "integrity": "sha512-TcbVRL4/O5ffI1RXFmQAFD3gwwT15AAdr1770x+RNqVvfBdoGVyhzOwCIyA5Vfc3fA1iJXFa+rE6buJZSoqlcw==", - "license": "GPL-3.0-or-later", - "dependencies": { - "@nextcloud/auth": "^2.5.3" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - } + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz", + "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] }, - "node_modules/@nextcloud/moment": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@nextcloud/moment/-/moment-1.3.5.tgz", - "integrity": "sha512-sQjQ/D40sdedtq4ywuANSxqG0VhIB/i+QtZ6Voz3nyZWhkyyqGxdj9rQu9AyEvas3/Jlspdom5chc+a8jOmHxQ==", - "license": "GPL-3.0-or-later", - "dependencies": { - "@nextcloud/l10n": "^3.4.0", - "moment": "^2.30.1" - }, - "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" - } + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz", + "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] }, - "node_modules/@nextcloud/paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@nextcloud/paths/-/paths-2.2.1.tgz", - "integrity": "sha512-M3ShLjrxR7B48eKThLMoqbxTqTKyQXcwf9TgeXQGbCIhiHoXU6as5j8l5qNv/uZlANokVdowpuWHBi3b2+YNNA==", - "license": "GPL-3.0-or-later", - "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" - } + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz", + "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@nextcloud/router": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-3.1.0.tgz", - "integrity": "sha512-e4dkIaxRSwdZJlZFpn9x03QgBn/Sa2hN1hp/BA7+AbzykmSAlKuWfdmX8j/8ewrLpQwYmZR23IZO9XwpJXq2Uw==", - "license": "GPL-3.0-or-later", - "dependencies": { - "@nextcloud/typings": "^1.10.0" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - } + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz", + "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@nextcloud/sharing": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@nextcloud/sharing/-/sharing-0.2.5.tgz", - "integrity": "sha512-B3K5Dq9b5dexDA5n3AAuCF69Huwhrpw0J72fsVXV4KpPdImjhVPlExAv5o70AoXa+OqN4Rwn6gqJw+3ED892zg==", - "license": "GPL-3.0-or-later", - "dependencies": { - "@nextcloud/initial-state": "^2.2.0" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" - } + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz", + "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@nextcloud/stylelint-config": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@nextcloud/stylelint-config/-/stylelint-config-3.1.0.tgz", - "integrity": "sha512-ZKr/AeqfcqIziJAxnN4K0ldoGz8zWj8pUTov4eloqfaCgvJxcQkt2ldHJfxbutNq8uFkbvRYagkufaYxjC4FlQ==", + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz", + "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rushstack/node-core-library": { + "version": "5.23.1", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.23.1.tgz", + "integrity": "sha512-wlKmIKIYCKuCASbITvOxLZXepPbwXvrv7S6ig6XNWFchSyhL/E2txmVXspHY49Wu2dzf7nI27a2k/yV5BA3EiA==", "dev": true, - "license": "AGPL-3.0-or-later", + "license": "MIT", "dependencies": { - "stylelint-use-logical": "^2.1.2" - }, - "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" + "ajv": "~8.18.0", + "ajv-draft-04": "~1.0.0", + "ajv-formats": "~3.0.1", + "fs-extra": "~11.3.0", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.7.4" }, "peerDependencies": { - "stylelint": "^16.13.2", - "stylelint-config-recommended-scss": "^15.0.1", - "stylelint-config-recommended-vue": "^1.5.0" + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@nextcloud/timezones": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@nextcloud/timezones/-/timezones-0.2.0.tgz", - "integrity": "sha512-1mwQ+asTFOgv9rxPoAMEbDF8JfnenIa2EGNS+8MATCyi6WXxYh0Lhkaq1d3l2+xNbUPHgMnk4cRYsvIo319lkA==", - "license": "AGPL-3.0-or-later", + "node_modules/@rushstack/node-core-library/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", "dependencies": { - "ical.js": "^2.1.0" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, - "engines": { - "node": "^20 || ^22" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@nextcloud/typings": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@nextcloud/typings/-/typings-1.10.0.tgz", - "integrity": "sha512-SMC42rDjOH3SspPTLMZRv76ZliHpj2JJkF8pGLP8l1QrVTZxE47Qz5qeKmbj2VL+dRv2e/NgixlAFmzVnxkhqg==", - "license": "GPL-3.0-or-later", - "dependencies": { - "@types/jquery": "3.5.16" + "node_modules/@rushstack/node-core-library/node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || ^24.0.0" + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "node_modules/@nextcloud/vue": { - "version": "8.28.0", - "resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-8.28.0.tgz", - "integrity": "sha512-m0Ei6LpySq5OBb2zNqOx5vasDsmmiDTYtCoWb20ZBCT3+uk3D2m02US9g+1dS4v/Gb4BcwFLYm5mwlRH9zNERw==", - "license": "AGPL-3.0-or-later", + "node_modules/@rushstack/node-core-library/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.1.0", - "@linusborg/vue-simple-portal": "^0.1.5", - "@nextcloud/auth": "^2.4.0", - "@nextcloud/axios": "^2.5.0", - "@nextcloud/browser-storage": "^0.4.0", - "@nextcloud/capabilities": "^1.2.0", - "@nextcloud/event-bus": "^3.3.2", - "@nextcloud/initial-state": "^2.2.0", - "@nextcloud/l10n": "^3.4.0", - "@nextcloud/logger": "^3.0.2", - "@nextcloud/router": "^3.0.1", - "@nextcloud/sharing": "^0.2.3", - "@nextcloud/timezones": "^0.2.0", - "@nextcloud/vue-select": "^3.25.1", - "@vueuse/components": "^11.0.0", - "@vueuse/core": "^11.0.0", - "blurhash": "^2.0.5", - "clone": "^2.1.2", - "debounce": "^2.2.0", - "dompurify": "^3.2.4", - "emoji-mart-vue-fast": "^15.0.4", - "escape-html": "^1.0.3", - "floating-vue": "^1.0.0-beta.19", - "focus-trap": "^7.4.3", - "linkify-string": "^4.0.0", - "md5": "^2.3.0", - "p-queue": "^8.1.0", - "rehype-external-links": "^3.0.0", - "rehype-highlight": "^7.0.2", - "rehype-react": "^7.1.2", - "remark-breaks": "^4.0.0", - "remark-parse": "^11.0.0", - "remark-rehype": "^11.0.0", - "remark-unlink-protocols": "^1.0.0", - "splitpanes": "^2.4.1", - "string-length": "^5.0.1", - "striptags": "^3.2.0", - "tabbable": "^6.2.0", - "tributejs": "^5.1.3", - "unified": "^11.0.1", - "unist-builder": "^4.0.0", - "unist-util-visit": "^5.0.0", - "vue": "^2.7.16", - "vue-color": "^2.8.1", - "vue-frag": "^1.4.3", - "vue-router": "^3.6.5", - "vue2-datepicker": "^3.11.0" + "ajv": "^8.0.0" }, - "engines": { - "node": "^20.0.0", - "npm": "^10.0.0" + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "node_modules/@nextcloud/vue-select": { - "version": "3.25.1", - "resolved": "https://registry.npmjs.org/@nextcloud/vue-select/-/vue-select-3.25.1.tgz", - "integrity": "sha512-jqCi4G+Q0H6+Hm8wSN3vRX2+eXG2jXR2bwBX/sErVEsH5UaxT4Nb7KqgdeIjVfeF7ccIdRqpmIb4Pkf0lao67w==", + "node_modules/@rushstack/node-core-library/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rushstack/problem-matcher": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@rushstack/problem-matcher/-/problem-matcher-0.2.1.tgz", + "integrity": "sha512-gulfhBs6n+I5b7DvjKRfhMGyUejtSgOHTclF/eONr8hcgF1APEDjhxIsfdUYYMzC3rvLwGluqLjbwCFZ8nxrog==", + "dev": true, "license": "MIT", - "engines": { - "node": "^20.0.0" - }, "peerDependencies": { - "vue": "2.x" + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@nextcloud/webpack-vue-config": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@nextcloud/webpack-vue-config/-/webpack-vue-config-6.3.0.tgz", - "integrity": "sha512-Reciadvarap6j3d0arMH34zNiXx6d7B5QXDiosV6ZwDu63mR1lSm4ZUdLr6lv4gfmrADmQ5iP7PQMr99MBeTvw==", + "node_modules/@rushstack/rig-package": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.7.3.tgz", + "integrity": "sha512-aAA518n6wxxjCfnTAOjQnm7ngNE0FVHxHAw2pxKlIhxrMn0XQjGcXKF0oKWpjBgJOmsaJpVob/v+zr3zxgPWuA==", "dev": true, - "hasInstallScript": true, - "engines": { - "node": "^20.0.0", - "npm": "^9.0.0 || ^10.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.22.9", - "babel-loader": "^10.0.0", - "css-loader": "^7.1.1", - "node-polyfill-webpack-plugin": "4.0.0", - "sass": "^1.64.2", - "sass-loader": "^16.0.2", - "style-loader": "^4.0.0", - "ts-loader": "^9.4.4", - "vue": "^2.7.16 || ^3.5.13", - "vue-loader": "^15.11.1 || ^17.4.2", - "webpack": "^5.88.2", - "webpack-cli": "^6.0.1", - "webpack-dev-server": "^5.0.2" - } - }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { - "version": "5.1.1-v1", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", - "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "license": "MIT", + "dependencies": { + "jju": "~1.4.0", + "resolve": "~1.22.1" + } + }, + "node_modules/@rushstack/terminal": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.24.0.tgz", + "integrity": "sha512-8ZQS4MMaGsv27EXCBiH7WMPkRZrffeDoIevs6z9TM5dzqiY6+Hn4evfK/G+gvgBTjfvfkHIZPQQmalmI2sM4TQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "eslint-scope": "5.1.1" + "@rushstack/node-core-library": "5.23.1", + "@rushstack/problem-matcher": "0.2.1", + "supports-color": "~8.1.1" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@rushstack/terminal/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "has-flag": "^4.0.0" }, "engines": { - "node": ">= 8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@rushstack/ts-command-line": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.3.9.tgz", + "integrity": "sha512-GIHqU+sRGQ3LGWAZu1O+9Yh++qwtyNIIGuNbcWHJjBTm2qRez0cwINUHZ+pQLR8UuzZDcMajrDaNbUYoaL/XtQ==", "dev": true, "license": "MIT", - "peer": true, - "engines": { - "node": ">= 8" + "dependencies": { + "@rushstack/terminal": "0.24.0", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@rushstack/ts-command-line/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" + "sprintf-js": "~1.0.2" } }, - "node_modules/@nolyfill/is-core-module": { - "version": "1.0.39", - "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", - "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "node_modules/@sindresorhus/base62": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/base62/-/base62-1.0.0.tgz", + "integrity": "sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA==", "dev": true, "license": "MIT", - "peer": true, "engines": { - "node": ">=12.4.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@parcel/watcher": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", - "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "node_modules/@stylistic/eslint-plugin": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.10.0.tgz", + "integrity": "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "detect-libc": "^1.0.3", - "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "node-addon-api": "^7.0.0" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/types": "^8.56.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.3" }, "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.1", - "@parcel/watcher-darwin-arm64": "2.5.1", - "@parcel/watcher-darwin-x64": "2.5.1", - "@parcel/watcher-freebsd-x64": "2.5.1", - "@parcel/watcher-linux-arm-glibc": "2.5.1", - "@parcel/watcher-linux-arm-musl": "2.5.1", - "@parcel/watcher-linux-arm64-glibc": "2.5.1", - "@parcel/watcher-linux-arm64-musl": "2.5.1", - "@parcel/watcher-linux-x64-glibc": "2.5.1", - "@parcel/watcher-linux-x64-musl": "2.5.1", - "@parcel/watcher-win32-arm64": "2.5.1", - "@parcel/watcher-win32-ia32": "2.5.1", - "@parcel/watcher-win32-x64": "2.5.1" + "peerDependencies": { + "eslint": "^9.0.0 || ^10.0.0" } }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", - "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", - "cpu": [ - "x64" - ], + "node_modules/@stylistic/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.1.tgz", + "integrity": "sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, "engines": { - "node": ">= 10.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", - "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, + "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">= 10.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@raruto/leaflet-elevation": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@raruto/leaflet-elevation/-/leaflet-elevation-2.5.2.tgz", - "integrity": "sha512-bXWxDe72MeD5eBn6u06mF9agf2PFUg81OvT6QBQRacg+fkI4UHYL9eLcbvFo5uHltf7bN/M6f+FWsHMfgc9+QA==", - "license": "GPL-3.0", - "peerDependencies": { - "@tmcw/togeojson": "5.6.2", - "d3": "7.8.4", - "leaflet": "^1.7.0", - "leaflet-i18n": "^0.3.1" + "node_modules/@stylistic/eslint-plugin/node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@rtsao/scc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "node_modules/@stylistic/eslint-plugin/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, "node_modules/@tmcw/togeojson": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/@tmcw/togeojson/-/togeojson-5.6.2.tgz", "integrity": "sha512-Tj0apuZI24WxF5rVTWsrQG2rmBQhl1TYeLvrTVRpU9G+1Ey2s32Luy3/DBQzULjJtVRD4sW3TjRldNc9a93ohA==", + "license": "BSD-2-Clause", "peer": true, "peerDependencies": { "@types/geojson": "*" @@ -3109,51 +2867,12 @@ "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", "license": "MIT" }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bonjour": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", - "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "node_modules/@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } + "license": "MIT" }, "node_modules/@types/debug": { "version": "4.1.12", @@ -3170,61 +2889,28 @@ "integrity": "sha512-qZ72SFTgUAZ5a7Tj6kf2SHLetiH5S6f8G5frB2SPQ3EyF02kxdyBFf4Tz4banE3xCgGnKgWLt//a6VuYHKYJTg==", "license": "MIT" }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "license": "MIT", - "peer": true - }, - "node_modules/@types/express": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz", - "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } + "license": "MIT" }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.6", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", - "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "@types/estree": "*" } }, "node_modules/@types/geojson": { @@ -3251,25 +2937,6 @@ "@types/unist": "*" } }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@types/http-proxy": { - "version": "1.17.16", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz", - "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/jquery": { "version": "3.5.16", "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz", @@ -3283,16 +2950,8 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "license": "MIT", - "peer": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/leaflet": { "version": "1.9.21", @@ -3317,140 +2976,40 @@ "@types/unist": "*" } }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "license": "MIT" }, - "node_modules/@types/node": { - "version": "24.0.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.14.tgz", - "integrity": "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw==", - "license": "MIT", - "peer": true, - "dependencies": { - "undici-types": "~7.8.0" - } - }, - "node_modules/@types/node-forge": { - "version": "1.3.13", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.13.tgz", - "integrity": "sha512-zePQJSW5QkwSHKRApqWCVKeKoSOt4xvEnLENZPjyvm9Ezdf/EyDeJM7jqLzOwjVICQQzvLZ63T55MKdJB5H6ww==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/pbf": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==", "license": "MIT" }, - "node_modules/@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/@types/react": { - "version": "19.1.8", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz", - "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "license": "MIT", "peer": true, "dependencies": { - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, - "node_modules/@types/retry": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", - "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/@types/semver": { "version": "7.7.0", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==", "license": "MIT" }, - "node_modules/@types/send": { - "version": "0.17.5", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", - "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-index": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", - "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", - "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" - } - }, "node_modules/@types/sizzle": { "version": "2.3.9", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.9.tgz", "integrity": "sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==", "license": "MIT" }, - "node_modules/@types/sockjs": { - "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/supercluster": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz", @@ -3485,281 +3044,145 @@ "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", "license": "MIT" }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", - "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.1.tgz", + "integrity": "sha512-+MuHQlHiEr00Of/IQbE/MmEoi44znZHbR/Pz7Opq4HryUOlRi+/44dro9Ycy8Fyo+/024IWtw8m4JUMCGTYxDg==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/type-utils": "7.18.0", - "@typescript-eslint/utils": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", - "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4" + "@typescript-eslint/tsconfig-utils": "^8.59.1", + "@typescript-eslint/types": "^8.59.1", + "debug": "^4.4.3" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", - "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.1.tgz", + "integrity": "sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0" - }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", - "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.1.tgz", + "integrity": "sha512-/0nEyPbX7gRsk0Uwfe4ALwwgxuA66d/l2mhRDNlAvaj4U3juhUtJNq0DsY8M2AYwwb9rEq2hrC3IcIcEt++iJA==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/utils": "7.18.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@vitejs/plugin-vue2": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue2/-/plugin-vue2-2.3.4.tgz", + "integrity": "sha512-LgqtRRedJb1KdmgcllwGX0gtlPvOvtR6pITXmqxGwQhBZaAysg0Hd7wvj3sjCsj4+PENWsqS7O+ceYSOgJ+H9g==", "dev": true, "license": "MIT", - "peer": true, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^14.18.0 || >= 16.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "vue": "^2.7.0-0" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", - "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", "dev": true, - "license": "BSD-2-Clause", - "peer": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@volar/source-map": "2.4.28" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } + "license": "MIT" }, - "node_modules/@typescript-eslint/utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", - "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", - "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "node_modules/@vue/compiler-core": { + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.33.tgz", + "integrity": "sha512-3PZLQwFw4Za3TC8t0FvTy3wI16Kt+pmwcgNZca4Pj9iWL2E72a/gZlpBtAJvEdDMdCxdG/qq0C7PN0bsJuv0Rw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@typescript-eslint/types": "7.18.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "@babel/parser": "^7.29.2", + "@vue/shared": "3.5.33", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/@vue/compiler-core/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", "dev": true, - "license": "Apache-2.0", - "peer": true, + "license": "BSD-2-Clause", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=0.12" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "license": "ISC" - }, - "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", - "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", - "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", - "cpu": [ - "x64" - ], + "node_modules/@vue/compiler-dom": { + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.33.tgz", + "integrity": "sha512-PXq0yrfCLzzL07rbXO4awtXY1Z06LG2eu6Adg3RJFa/j3Cii217XxxLXG22N330gw7GmALCY0Z8RgXEviwgpjA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true + "dependencies": { + "@vue/compiler-core": "3.5.33", + "@vue/shared": "3.5.33" + } }, "node_modules/@vue/compiler-sfc": { "version": "2.7.16", @@ -3783,92 +3206,35 @@ "node": ">=0.10.0" } }, - "node_modules/@vue/component-compiler-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", - "integrity": "sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==", - "license": "MIT", - "dependencies": { - "consolidate": "^0.15.1", - "hash-sum": "^1.0.2", - "lru-cache": "^4.1.2", - "merge-source-map": "^1.1.0", - "postcss": "^7.0.36", - "postcss-selector-parser": "^6.0.2", - "source-map": "~0.6.1", - "vue-template-es2015-compiler": "^1.9.0" - }, - "optionalDependencies": { - "prettier": "^1.18.2 || ^2.0.0" - } - }, - "node_modules/@vue/component-compiler-utils/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "license": "ISC", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/@vue/component-compiler-utils/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "license": "ISC" - }, - "node_modules/@vue/component-compiler-utils/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", + "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/@vue/component-compiler-utils/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" + "de-indent": "^1.0.2", + "he": "^1.2.0" } }, - "node_modules/@vue/component-compiler-utils/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "license": "ISC" - }, - "node_modules/@vue/eslint-config-typescript": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-13.0.0.tgz", - "integrity": "sha512-MHh9SncG/sfqjVqjcuFLOLD6Ed4dRAis4HNt0dXASeAuLqIAx4YMB1/m2o4pUKK1vCt8fUvYG8KKX2Ot3BVZTg==", + "node_modules/@vue/language-core": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.0.tgz", + "integrity": "sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@typescript-eslint/eslint-plugin": "^7.1.1", - "@typescript-eslint/parser": "^7.1.1", - "vue-eslint-parser": "^9.3.1" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" + "@volar/language-core": "~2.4.11", + "@vue/compiler-dom": "^3.5.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.5.0", + "alien-signals": "^0.4.9", + "minimatch": "^9.0.3", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" }, "peerDependencies": { - "eslint": "^8.56.0", - "eslint-plugin-vue": "^9.0.0", - "typescript": ">=4.7.4" + "typescript": "*" }, "peerDependenciesMeta": { "typescript": { @@ -3876,6 +3242,13 @@ } } }, + "node_modules/@vue/shared": { + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.33.tgz", + "integrity": "sha512-5vR2QIlmaLG77Ygd4pMP6+SGQ5yox9VhtnbDWTy9DzMzdmeLxZ1QqxrywEZ9sa1AVubfIJyaCG3ytyWU81ufcQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@vue/tsconfig": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.5.1.tgz", @@ -3914,371 +3287,106 @@ "@vue/composition-api": "^1.0.0-rc.1", "vue": "^3.0.0-0 || ^2.6.0" }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } - } - }, - "node_modules/@vueuse/core": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-11.3.0.tgz", - "integrity": "sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==", - "license": "MIT", - "dependencies": { - "@types/web-bluetooth": "^0.0.20", - "@vueuse/metadata": "11.3.0", - "@vueuse/shared": "11.3.0", - "vue-demi": ">=0.14.10" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/@vueuse/core/node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } - } - }, - "node_modules/@vueuse/metadata": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-11.3.0.tgz", - "integrity": "sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/@vueuse/shared": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-11.3.0.tgz", - "integrity": "sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==", - "license": "MIT", - "dependencies": { - "vue-demi": ">=0.14.10" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/@vueuse/shared/node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } - } - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.13.2", - "@webassemblyjs/helper-api-error": "1.13.2", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/wasm-gen": "1.14.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/helper-wasm-section": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-opt": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1", - "@webassemblyjs/wast-printer": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-api-error": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webpack-cli/configtest": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-3.0.1.tgz", - "integrity": "sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "webpack": "^5.82.0", - "webpack-cli": "6.x.x" + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } } }, - "node_modules/@webpack-cli/info": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-3.0.1.tgz", - "integrity": "sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==", - "dev": true, + "node_modules/@vueuse/core": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-11.3.0.tgz", + "integrity": "sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==", "license": "MIT", - "peer": true, - "engines": { - "node": ">=18.12.0" + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "11.3.0", + "@vueuse/shared": "11.3.0", + "vue-demi": ">=0.14.10" }, - "peerDependencies": { - "webpack": "^5.82.0", - "webpack-cli": "6.x.x" + "funding": { + "url": "https://github.com/sponsors/antfu" } }, - "node_modules/@webpack-cli/serve": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-3.0.1.tgz", - "integrity": "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==", - "dev": true, + "node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, "license": "MIT", - "peer": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, "engines": { - "node": ">=18.12.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" }, "peerDependencies": { - "webpack": "^5.82.0", - "webpack-cli": "6.x.x" + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" }, "peerDependenciesMeta": { - "webpack-dev-server": { + "@vue/composition-api": { "optional": true } } }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "license": "Apache-2.0", - "peer": true - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dev": true, + "node_modules/@vueuse/metadata": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-11.3.0.tgz", + "integrity": "sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g==", "license": "MIT", - "peer": true, - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" + "funding": { + "url": "https://github.com/sponsors/antfu" } }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, + "node_modules/@vueuse/shared": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-11.3.0.tgz", + "integrity": "sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==", "license": "MIT", - "peer": true, "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "vue-demi": ">=0.14.10" }, - "engines": { - "node": ">= 0.6" + "funding": { + "url": "https://github.com/sponsors/antfu" } }, - "node_modules/accepts/node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, + "node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, "license": "MIT", - "peer": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, "engines": { - "node": ">= 0.6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } } }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4286,37 +3394,22 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-phases": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", - "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.13.0" - }, - "peerDependencies": { - "acorn": "^8.14.0" - } - }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -4328,61 +3421,12 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "license": "MIT", - "peer": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT", - "peer": true - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "node_modules/alien-signals": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-0.4.14.tgz", + "integrity": "sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==", "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "license": "Apache-2.0", - "peer": true, - "bin": { - "ansi-html": "bin/ansi-html" - } + "license": "MIT" }, "node_modules/ansi-regex": { "version": "5.0.1", @@ -4412,28 +3456,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/are-docs-informative": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=14" } @@ -4446,151 +3474,25 @@ "license": "Python-2.0", "peer": true }, - "node_modules/array-buffer-byte-length": { + "node_modules/array-find-index": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/array-includes": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", - "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.0", - "es-object-atoms": "^1.1.1", - "get-intrinsic": "^1.3.0", - "is-string": "^1.1.1", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", - "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-shim-unscopables": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", - "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", - "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, "license": "MIT", "peer": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, "node_modules/asn1.js": { @@ -4599,7 +3501,6 @@ "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -4611,8 +3512,7 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/assert": { "version": "2.1.0", @@ -4620,7 +3520,6 @@ "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.2", "is-nan": "^1.3.2", @@ -4640,17 +3539,6 @@ "node": ">=8" } }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -4663,7 +3551,6 @@ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "possible-typed-array-names": "^1.0.0" }, @@ -4685,69 +3572,6 @@ "proxy-from-env": "^1.1.0" } }, - "node_modules/babel-loader": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.0.0.tgz", - "integrity": "sha512-z8jt+EdS61AMw22nSfoNJAZ0vrtmhPRVi6ghL3rCeRZI8cdNYFiV5xeV3HbE7rlZZNmGH8BVccwWt8/ED0QOHA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "find-up": "^5.0.0" - }, - "engines": { - "node": "^18.20.0 || ^20.10.0 || >=22.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0", - "webpack": ">=5.61.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", - "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/compat-data": "^7.27.7", - "@babel/helper-define-polyfill-provider": "^0.6.5", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", - "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5", - "core-js-compat": "^3.43.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", - "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -4789,46 +3613,21 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "peer": true - }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "license": "MIT", - "engines": { - "node": "*" - } + "license": "MIT" }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "node_modules/baseline-browser-mapping": { + "version": "2.10.23", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.23.tgz", + "integrity": "sha512-xwVXGqevyKPsiuQdLj+dZMVjidjJV508TBqexND5HrF89cGdCYCJFB3qhcxRHSeMctdCfbR1jrxBajhDy7o29g==", "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "license": "MIT" - }, "node_modules/blurhash": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/blurhash/-/blurhash-2.0.5.tgz", @@ -4840,90 +3639,14 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/bonjour-service": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", - "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" - } + "license": "MIT" }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/brace-expansion": { "version": "2.0.2", @@ -4940,7 +3663,6 @@ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -4953,8 +3675,17 @@ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", "dev": true, + "license": "MIT" + }, + "node_modules/browser-resolve": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", + "dev": true, "license": "MIT", - "peer": true + "dependencies": { + "resolve": "^1.17.0" + } }, "node_modules/browserify-aes": { "version": "1.2.0", @@ -4962,7 +3693,6 @@ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -4978,7 +3708,6 @@ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", @@ -4991,7 +3720,6 @@ "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", @@ -5005,7 +3733,6 @@ "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^5.2.1", "randombytes": "^2.1.0", @@ -5021,7 +3748,6 @@ "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "bn.js": "^5.2.1", "browserify-rsa": "^4.1.0", @@ -5043,8 +3769,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/browserify-sign/node_modules/readable-stream": { "version": "2.3.8", @@ -5052,7 +3777,6 @@ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -5068,8 +3792,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/browserify-sign/node_modules/string_decoder": { "version": "1.1.1", @@ -5077,7 +3800,6 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -5087,8 +3809,7 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/browserify-zlib": { "version": "0.2.0", @@ -5096,15 +3817,15 @@ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "pako": "~1.0.5" } }, "node_modules/browserslist": { - "version": "4.25.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", - "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, "funding": [ { "type": "opencollective", @@ -5121,10 +3842,11 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001726", - "electron-to-chromium": "^1.5.173", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.3" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -5133,149 +3855,69 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "node_modules/browserslist-to-esbuild": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/browserslist-to-esbuild/-/browserslist-to-esbuild-2.1.1.tgz", + "integrity": "sha512-KN+mty6C3e9AN8Z5dI1xeN15ExcRNeISoC3g7V0Kax/MMF9MSoYA2G7lkTTcVUFntiEjkpI0HNgqJC1NjdyNUw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], "license": "MIT", - "peer": true, "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" + "meow": "^13.0.0" + }, + "bin": { + "browserslist-to-esbuild": "cli/index.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "browserslist": "*" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT", - "peer": true - }, "node_modules/buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", "dev": true, - "license": "MIT", - "peer": true - }, - "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==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, "node_modules/builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/builtins": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", - "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "semver": "^7.0.0" - } - }, - "node_modules/builtins/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/bundle-name": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", - "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "run-applescript": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/byte-length/-/byte-length-1.0.2.tgz", - "integrity": "sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==", - "license": "MIT" - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } + "license": "MIT" + }, + "node_modules/byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/byte-length/-/byte-length-1.0.2.tgz", + "integrity": "sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==", + "license": "MIT" }, "node_modules/cacheable": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-1.10.1.tgz", - "integrity": "sha512-Fa2BZY0CS9F0PFc/6aVA6tgpOdw+hmv9dkZOlHXII5v5Hw+meJBIWDcPrG9q/dXxGcNbym5t77fzmawrBQfTmQ==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.3.4.tgz", + "integrity": "sha512-djgxybDbw9fL/ZWMI3+CE8ZilNxcwFkVtDc1gJ+IlOSSWkSMPQabhV/XCHTQ6pwwN6aivXPZ43omTooZiX06Ew==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "hookified": "^1.10.0", - "keyv": "^5.3.4" + "@cacheable/memory": "^2.0.8", + "@cacheable/utils": "^2.4.0", + "hookified": "^1.15.0", + "keyv": "^5.6.0", + "qified": "^0.9.0" } }, "node_modules/cacheable/node_modules/keyv": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.3.4.tgz", - "integrity": "sha512-ypEvQvInNpUe+u+w8BIcPkQvEqXquyyibWE/1NB5T2BTzIpS5cGEV1LZskDzPSTvNAaT4+5FutvzlvnkxOSKlw==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@keyv/serialize": "^1.0.3" + "@keyv/serialize": "^1.1.1" } }, "node_modules/call-bind": { @@ -5284,7 +3926,6 @@ "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", @@ -5317,7 +3958,6 @@ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" @@ -5347,9 +3987,10 @@ "license": "MIT" }, "node_modules/caniuse-lite": { - "version": "1.0.30001727", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", - "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", + "version": "1.0.30001791", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001791.tgz", + "integrity": "sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -5366,24 +4007,6 @@ ], "license": "CC-BY-4.0" }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/char-regex": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.2.tgz", @@ -5424,7 +4047,6 @@ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "readdirp": "^4.0.1" }, @@ -5435,23 +4057,12 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.0" - } - }, "node_modules/cipher-base": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1" @@ -5475,36 +4086,6 @@ "node": ">=0.8" } }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/clone-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -5535,14 +4116,6 @@ "license": "MIT", "peer": true }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -5566,172 +4139,58 @@ } }, "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT", - "peer": true - }, - "node_modules/comment-parser": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", - "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", - "dev": true, + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "license": "MIT", "peer": true, "engines": { - "node": ">= 12.0.0" + "node": ">= 10" } }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "node_modules/comment-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.6.tgz", + "integrity": "sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", - "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", - "dev": true, - "peer": true, - "dependencies": { - "bytes": "3.1.2", - "compressible": "~2.0.18", - "debug": "2.6.9", - "negotiator": "~0.6.4", - "on-headers": "~1.1.0", - "safe-buffer": "5.2.1", - "vary": "~1.1.2" - }, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "2.0.0" + "node": ">= 12.0.0" } }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "node_modules/commenting": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/commenting/-/commenting-1.1.0.tgz", + "integrity": "sha512-YeNK4tavZwtH7jEgK1ZINXzLKm6DZdEMfsaaieOsCAN0S8vsY7UeuO3Q7d/M018EFgE+IeUAuBOKkFccBZsUZA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, - "node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.8" - } + "license": "MIT" }, "node_modules/console-browserify": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", - "dev": true, - "peer": true - }, - "node_modules/consolidate": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", - "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", - "license": "MIT", - "dependencies": { - "bluebird": "^3.1.1" - }, - "engines": { - "node": ">= 0.10.0" - } + "dev": true }, "node_modules/constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/core-js": { "version": "3.37.0", @@ -5745,14 +4204,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.44.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.44.0.tgz", - "integrity": "sha512-JepmAj2zfl6ogy34qfWtcE7nHKAJnKsQFRn++scjVS2bZFllwptzw61BZcZFYBPpUznLfAvh0LGhxKppk04ClA==", + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "browserslist": "^4.25.1" + "browserslist": "^4.28.1" }, "funding": { "type": "opencollective", @@ -5764,8 +4222,7 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/corslite": { "version": "0.0.6", @@ -5774,9 +4231,9 @@ "license": "BSD" }, "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", "dev": true, "license": "MIT", "peer": true, @@ -5807,7 +4264,6 @@ "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.1.0", "elliptic": "^6.5.3" @@ -5818,8 +4274,7 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/create-hash": { "version": "1.2.0", @@ -5827,7 +4282,6 @@ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -5842,7 +4296,6 @@ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -5852,13 +4305,19 @@ "sha.js": "^2.4.8" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -5883,7 +4342,6 @@ "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "browserify-cipher": "^1.0.1", "browserify-sign": "^4.2.3", @@ -5906,75 +4364,26 @@ } }, "node_modules/css-functions-list": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz", - "integrity": "sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.3.3.tgz", + "integrity": "sha512-8HFEBPKhOpJPEPu70wJJetjKta86Gw9+CCyCnB3sui2qQfOvRyqBy4IKLKKAwdMpWb2lHXWk9Wb4Z6AmaUT1Pg==", "dev": true, "license": "MIT", "peer": true, "engines": { - "node": ">=12 || >=16" - } - }, - "node_modules/css-loader": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", - "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", - "license": "MIT", - "peer": true, - "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.33", - "postcss-modules-extract-imports": "^3.1.0", - "postcss-modules-local-by-default": "^4.0.5", - "postcss-modules-scope": "^3.2.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.27.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, - "node_modules/css-loader/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/css-tree": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", - "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "mdn-data": "2.12.2", - "source-map-js": "^1.0.1" + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" @@ -5990,6 +4399,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -5999,15 +4409,16 @@ } }, "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, "node_modules/d3": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.4.tgz", "integrity": "sha512-q2WHStdhiBtD8DMmhDPyJmXUxr6VWRngKyiJ5EfXMxPw+tqT6BhNjhJZ4w3BHsNm3QoVfZLY8Orq/qPFczwKRA==", + "license": "ISC", "peer": true, "dependencies": { "d3-array": "3", @@ -6049,6 +4460,7 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", "peer": true, "dependencies": { "internmap": "1 - 2" @@ -6061,6 +4473,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", "peer": true, "engines": { "node": ">=12" @@ -6070,6 +4483,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", "peer": true, "dependencies": { "d3-dispatch": "1 - 3", @@ -6086,6 +4500,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", "peer": true, "dependencies": { "d3-path": "1 - 3" @@ -6098,6 +4513,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", "peer": true, "engines": { "node": ">=12" @@ -6107,6 +4523,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", "peer": true, "dependencies": { "d3-array": "^3.2.0" @@ -6119,6 +4536,7 @@ "version": "6.0.4", "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", "peer": true, "dependencies": { "delaunator": "5" @@ -6131,6 +4549,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", "peer": true, "engines": { "node": ">=12" @@ -6140,6 +4559,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", "peer": true, "dependencies": { "d3-dispatch": "1 - 3", @@ -6153,6 +4573,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", "peer": true, "dependencies": { "commander": "7", @@ -6174,31 +4595,11 @@ "node": ">=12" } }, - "node_modules/d3-dsv/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "peer": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/d3-dsv/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/d3-ease": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", "peer": true, "engines": { "node": ">=12" @@ -6208,6 +4609,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", "peer": true, "dependencies": { "d3-dsv": "1 - 3" @@ -6220,6 +4622,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", "peer": true, "dependencies": { "d3-dispatch": "1 - 3", @@ -6231,9 +4634,10 @@ } }, "node_modules/d3-format": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", - "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", "peer": true, "engines": { "node": ">=12" @@ -6243,6 +4647,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", "peer": true, "dependencies": { "d3-array": "2.5.0 - 3" @@ -6255,6 +4660,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", "peer": true, "engines": { "node": ">=12" @@ -6264,6 +4670,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", "peer": true, "dependencies": { "d3-color": "1 - 3" @@ -6276,6 +4683,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", "peer": true, "engines": { "node": ">=12" @@ -6285,6 +4693,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", "peer": true, "engines": { "node": ">=12" @@ -6294,6 +4703,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", "peer": true, "engines": { "node": ">=12" @@ -6303,6 +4713,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", "peer": true, "engines": { "node": ">=12" @@ -6312,6 +4723,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", "peer": true, "dependencies": { "d3-array": "2.10.0 - 3", @@ -6328,6 +4740,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", "peer": true, "dependencies": { "d3-color": "1 - 3", @@ -6341,6 +4754,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", "peer": true, "engines": { "node": ">=12" @@ -6350,6 +4764,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", "peer": true, "dependencies": { "d3-path": "^3.1.0" @@ -6362,6 +4777,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", "peer": true, "dependencies": { "d3-array": "2 - 3" @@ -6374,6 +4790,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", "peer": true, "dependencies": { "d3-time": "1 - 3" @@ -6386,6 +4803,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", "peer": true, "engines": { "node": ">=12" @@ -6395,6 +4813,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", "peer": true, "dependencies": { "d3-color": "1 - 3", @@ -6414,6 +4833,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", "peer": true, "dependencies": { "d3-dispatch": "1 - 3", @@ -6435,69 +4855,19 @@ "node": ">= 12" } }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/date-format-parse": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/date-format-parse/-/date-format-parse-0.2.7.tgz", "integrity": "sha512-/+lyMUKoRogMuTeOVii6lUwjbVlesN9YRYLzZT/g3TEZ3uD9QnpjResujeEqUW+OSNbT7T1+SYdyEkTcRv+KDQ==", "license": "MIT" }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true, + "license": "MIT" + }, "node_modules/debounce": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/debounce/-/debounce-2.2.0.tgz", @@ -6511,9 +4881,9 @@ } }, "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -6545,40 +4915,7 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/default-browser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", - "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "bundle-name": "^4.1.0", - "default-browser-id": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", - "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, "node_modules/define-data-property": { "version": "1.1.4", @@ -6586,7 +4923,6 @@ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -6599,27 +4935,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -6633,9 +4954,10 @@ } }, "node_modules/delaunator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", - "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "license": "ISC", "peer": true, "dependencies": { "robust-predicates": "^3.0.2" @@ -6650,17 +4972,6 @@ "node": ">=0.4.0" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -6676,24 +4987,11 @@ "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, "node_modules/detect-europe-js": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/detect-europe-js/-/detect-europe-js-0.1.2.tgz", @@ -6714,6 +5012,19 @@ ], "license": "MIT" }, + "node_modules/detect-indent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.2.tgz", + "integrity": "sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -6721,7 +5032,6 @@ "dev": true, "license": "Apache-2.0", "optional": true, - "peer": true, "bin": { "detect-libc": "bin/detect-libc.js" }, @@ -6729,13 +5039,18 @@ "node": ">=0.10" } }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "node_modules/detect-newline": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-4.0.1.tgz", + "integrity": "sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==", "dev": true, "license": "MIT", - "peer": true + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/devlop": { "version": "1.1.0", @@ -6750,13 +5065,22 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", @@ -6768,8 +5092,7 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/dir-glob": { "version": "3.0.1", @@ -6785,34 +5108,6 @@ "node": ">=8" } }, - "node_modules/dns-packet": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -6829,20 +5124,6 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/domain-browser": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-5.7.0.tgz", - "integrity": "sha512-edTFu0M/7wO1pXY6GDxVNVW086uqwWYIHP98txhcPyV995X21JIH2DtYp33sQJOupYoXKe9RwTw2Ya2vWaquTQ==", - "dev": true, - "license": "Artistic-2.0", - "peer": true, - "engines": { - "node": ">=4" - }, - "funding": { - "url": "https://bevry.me/fund" - } - }, "node_modules/domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", @@ -6919,18 +5200,11 @@ "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==", "license": "ISC" }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/electron-to-chromium": { - "version": "1.5.183", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.183.tgz", - "integrity": "sha512-vCrDBYjQCAEefWGjlK3EpoSKfKbT10pR4XXPdn65q7snuNOZnthoVpBfZPykmDapOKfoD+MMIPG8ZjKyyc9oHA==", + "version": "1.5.344", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.344.tgz", + "integrity": "sha512-4MxfbmNDm+KPh066EZy+eUnkcDPcZ35wNmOWzFuh/ijvHsve6kbLTLURy88uCNK5FbpN+yk2nQY6BYh1GEt+wg==", + "dev": true, "license": "ISC" }, "node_modules/elliptic": { @@ -6939,7 +5213,6 @@ "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -6955,8 +5228,7 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/emoji-mart-vue-fast": { "version": "15.0.4", @@ -6979,40 +5251,6 @@ "license": "MIT", "peer": true }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.18.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz", - "integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -7038,24 +5276,10 @@ "node": ">=6" } }, - "node_modules/envinfo": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", - "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "dev": true, "license": "MIT", "peer": true, @@ -7063,76 +5287,6 @@ "is-arrayish": "^0.2.1" } }, - "node_modules/es-abstract": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -7151,13 +5305,6 @@ "node": ">= 0.4" } }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "license": "MIT", - "peer": true - }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -7185,43 +5332,53 @@ "node": ">= 0.4" } }, - "node_modules/es-shim-unscopables": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", - "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "peer": true, - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -7239,7 +5396,6 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -7248,636 +5404,431 @@ } }, "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.1.tgz", + "integrity": "sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.5.5", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", + "minimatch": "^10.2.4", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-compat-utils": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", - "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12" + "url": "https://eslint.org/donate" }, "peerDependencies": { - "eslint": ">=6.0.0" - } - }, - "node_modules/eslint-compat-utils/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" + "jiti": "*" }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-config-standard": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", - "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" + "peerDependenciesMeta": { + "jiti": { + "optional": true } - ], - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", - "eslint-plugin-promise": "^6.0.0" } }, - "node_modules/eslint-import-resolver-exports": { - "version": "1.0.0-beta.5", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-exports/-/eslint-import-resolver-exports-1.0.0-beta.5.tgz", - "integrity": "sha512-o6t0w7muUpXr7MkUVzD5igQoDfAQvTmcPp8HEAJdNF8eOuAO+yn6I/TTyMxz9ecCwzX7e02vzlkHURoScUuidg==", + "node_modules/eslint-config-flat-gitignore": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-flat-gitignore/-/eslint-config-flat-gitignore-2.3.0.tgz", + "integrity": "sha512-bg4ZLGgoARg1naWfsINUUb/52Ksw/K22K+T16D38Y8v+/sGwwIYrGvH/JBjOin+RQtxxC9tzNNiy4shnGtGyyQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "resolve.exports": "^2.0.0" + "@eslint/compat": "^2.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" }, "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" + "eslint": "^9.5.0 || ^10.0.0" } }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/eslint-plugin-antfu": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-antfu/-/eslint-plugin-antfu-3.2.2.tgz", + "integrity": "sha512-Qzixht2Dmd/pMbb5EnKqw2V8TiWHbotPlsORO8a+IzCLFwE0RxK8a9k4DCTFPzBwyxJzH+0m2Mn8IUGeGQkyUw==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", - "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "@nolyfill/is-core-module": "1.0.39", - "debug": "^4.4.0", - "get-tsconfig": "^4.10.0", - "is-bun-module": "^2.0.0", - "stable-hash": "^0.0.5", - "tinyglobby": "^0.2.13", - "unrs-resolver": "^1.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, "funding": { - "url": "https://opencollective.com/eslint-import-resolver-typescript" + "url": "https://github.com/sponsors/antfu" }, "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*", - "eslint-plugin-import-x": "*" - }, - "peerDependenciesMeta": { - "eslint-plugin-import": { - "optional": true - }, - "eslint-plugin-import-x": { - "optional": true - } + "eslint": "*" } }, - "node_modules/eslint-module-utils": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", - "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "node_modules/eslint-plugin-jsdoc": { + "version": "62.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.9.0.tgz", + "integrity": "sha512-PY7/X4jrVgoIDncUmITlUqK546Ltmx/Pd4Hdsu4CvSjryQZJI2mEV4vrdMufyTetMiZ5taNSqvK//BTgVUlNkA==", "dev": true, - "license": "MIT", - "peer": true, + "license": "BSD-3-Clause", "dependencies": { - "debug": "^3.2.7" + "@es-joy/jsdoccomment": "~0.86.0", + "@es-joy/resolve.exports": "1.2.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.6", + "debug": "^4.4.3", + "escape-string-regexp": "^4.0.0", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "html-entities": "^2.6.0", + "object-deep-merge": "^2.0.0", + "parse-imports-exports": "^0.2.4", + "semver": "^7.7.4", + "spdx-expression-parse": "^4.0.0", + "to-valid-identifier": "^1.0.0" }, "engines": { - "node": ">=4" + "node": "^20.19.0 || ^22.13.0 || >=24" }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "^2.1.1" + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0" } }, - "node_modules/eslint-plugin-es-x": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", - "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", + "node_modules/eslint-plugin-perfectionist": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-5.9.0.tgz", + "integrity": "sha512-8TWzg02zmnBdZwCkWLi8jhzqXI+fE7Z/RwV8SL6xD45tJ8Bp3wGuYL2XtQgfe/Wd0eBqOUX+s6ey73IyszvKTA==", "dev": true, - "funding": [ - "https://github.com/sponsors/ota-meshi", - "https://opencollective.com/eslint" - ], "license": "MIT", - "peer": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.1.2", - "@eslint-community/regexpp": "^4.11.0", - "eslint-compat-utils": "^0.5.1" + "@typescript-eslint/utils": "^8.58.2", + "natural-orderby": "^5.0.0" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^20.0.0 || >=22.0.0" }, "peerDependencies": { - "eslint": ">=8" + "eslint": "^8.45.0 || ^9.0.0 || ^10.0.0" } }, - "node_modules/eslint-plugin-import": { - "version": "2.32.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", - "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "node_modules/eslint-plugin-perfectionist/node_modules/@typescript-eslint/scope-manager": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.1.tgz", + "integrity": "sha512-LwuHQI4pDOYVKvmH2dkaJo6YZCSgouVgnS/z7yBPKBMvgtBvyLqiLy9Z6b7+m/TRcX1NFYUqZetI5Y+aT4GEfg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.9", - "array.prototype.findlastindex": "^1.2.6", - "array.prototype.flat": "^1.3.3", - "array.prototype.flatmap": "^1.3.3", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.1", - "hasown": "^2.0.2", - "is-core-module": "^2.16.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.1", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.9", - "tsconfig-paths": "^3.15.0" + "@typescript-eslint/types": "8.59.1", + "@typescript-eslint/visitor-keys": "8.59.1" }, "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/eslint-plugin-perfectionist/node_modules/@typescript-eslint/types": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.1.tgz", + "integrity": "sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/eslint-plugin-perfectionist/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.1.tgz", + "integrity": "sha512-OUd+vJS05sSkOip+BkZ/2NS8RMxrAAJemsC6vU3kmfLyeaJT0TftHkV9mcx2107MmsBVXXexhVu4F0TZXyMl4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "esutils": "^2.0.2" + "@typescript-eslint/project-service": "8.59.1", + "@typescript-eslint/tsconfig-utils": "8.59.1", + "@typescript-eslint/types": "8.59.1", + "@typescript-eslint/visitor-keys": "8.59.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "engines": { - "node": "*" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/eslint-plugin-jsdoc": { - "version": "46.10.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.10.1.tgz", - "integrity": "sha512-x8wxIpv00Y50NyweDUpa+58ffgSAI5sqe+zcZh33xphD0AVh+1kqr1ombaTRb7Fhpove1zfUuujlX9DWWBP5ag==", + "node_modules/eslint-plugin-perfectionist/node_modules/@typescript-eslint/utils": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.1.tgz", + "integrity": "sha512-3pIeoXhCeYH9FSCBI8P3iNwJlGuzPlYKkTlen2O9T1DSeeg8UG8jstq6BLk+Mda0qup7mgk4z4XL4OzRaxZ8LA==", "dev": true, - "license": "BSD-3-Clause", - "peer": true, + "license": "MIT", "dependencies": { - "@es-joy/jsdoccomment": "~0.41.0", - "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.1", - "debug": "^4.3.4", - "escape-string-regexp": "^4.0.0", - "esquery": "^1.5.0", - "is-builtin-module": "^3.2.1", - "semver": "^7.5.4", - "spdx-expression-parse": "^4.0.0" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.59.1", + "@typescript-eslint/types": "8.59.1", + "@typescript-eslint/typescript-estree": "8.59.1" }, "engines": { - "node": ">=16" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/eslint-plugin-n": { - "version": "16.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz", - "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==", + "node_modules/eslint-plugin-perfectionist/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.1.tgz", + "integrity": "sha512-LdDNl6C5iJExcM0Yh0PwAIBb9PrSiCsWamF/JyEZawm3kFDnRoaq3LGE4bpyRao/fWeGKKyw7icx0YxrLFC5Cg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "builtins": "^5.0.1", - "eslint-plugin-es-x": "^7.5.0", - "get-tsconfig": "^4.7.0", - "globals": "^13.24.0", - "ignore": "^5.2.4", - "is-builtin-module": "^3.2.1", - "is-core-module": "^2.12.1", - "minimatch": "^3.1.2", - "resolve": "^1.22.2", - "semver": "^7.5.3" + "@typescript-eslint/types": "8.59.1", + "eslint-visitor-keys": "^5.0.0" }, "engines": { - "node": ">=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=7.0.0" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/eslint-plugin-n/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/eslint-plugin-perfectionist/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "engines": { + "node": "18 || 20 || >=22" } }, - "node_modules/eslint-plugin-n/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/eslint-plugin-perfectionist/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, - "license": "ISC", - "peer": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "balanced-match": "^4.0.2" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" } }, - "node_modules/eslint-plugin-n/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "node_modules/eslint-plugin-perfectionist/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" }, "engines": { - "node": ">=10" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/eslint-plugin-promise": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz", - "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==", + "node_modules/eslint-plugin-perfectionist/node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, - "license": "ISC", - "peer": true, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18.12" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + "typescript": ">=4.8.4" } }, "node_modules/eslint-plugin-vue": { - "version": "9.33.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.33.0.tgz", - "integrity": "sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.9.0.tgz", + "integrity": "sha512-EFNNzu4HqtTRb5DJINpyd+u3bDdzETWDMpCzG+UBHz1tpsnMDCeOcf61u4Wy/cbXnMymK+MT9bjH7KcG1fItSw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "globals": "^13.24.0", "natural-compare": "^1.4.0", "nth-check": "^2.1.1", - "postcss-selector-parser": "^6.0.15", + "postcss-selector-parser": "^7.1.0", "semver": "^7.6.3", - "vue-eslint-parser": "^9.4.3", "xml-name-validator": "^4.0.0" }, "engines": { - "node": "^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { - "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-vue/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" + "@stylistic/eslint-plugin": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", + "@typescript-eslint/parser": "^7.0.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "vue-eslint-parser": "^10.0.0" }, - "engines": { - "node": ">=10" + "peerDependenciesMeta": { + "@stylistic/eslint-plugin": { + "optional": true + }, + "@typescript-eslint/parser": { + "optional": true + } } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, "license": "Apache-2.0", - "peer": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/eslint/node_modules/@eslint/plugin-kit": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz", + "integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/eslint/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, - "license": "BSD-2-Clause", - "peer": true, + "license": "MIT", "engines": { - "node": ">=4.0" + "node": "18 || 20 || >=22" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, - "license": "ISC", - "peer": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "balanced-match": "^4.0.2" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" } }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "node_modules/eslint/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, - "license": "BSD-2-Clause", - "peer": true, + "license": "BlueOak-1.0.0", "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "brace-expansion": "^5.0.5" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", "dev": true, - "license": "Apache-2.0", - "peer": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -7885,23 +5836,12 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -7909,59 +5849,44 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, "license": "BSD-2-Clause", - "peer": true, "engines": { "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">=4.0" + "node_modules/estree-toolkit": { + "version": "1.7.13", + "resolved": "https://registry.npmjs.org/estree-toolkit/-/estree-toolkit-1.7.13.tgz", + "integrity": "sha512-/fLCEcVBUgAtMkGXZHplPVyUv7wiSfsCGubBdM16n1iYCidPfyk1Kk1U0wAxLZADuA3z8k87DfVYXlBmHJeekg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": ">=1.0.7", + "@types/estree-jsx": ">=1.0.5" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - } - }, "node_modules/eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", @@ -7972,8 +5897,8 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.8.x" } @@ -7984,95 +5909,17 @@ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" } }, - "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/express/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, "node_modules/extend": { "version": "3.0.2", @@ -8084,8 +5931,8 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT", - "peer": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.3", @@ -8124,21 +5971,20 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/fast-uri": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, "funding": [ { "type": "github", @@ -8149,8 +5995,23 @@ "url": "https://opencollective.com/fastify" } ], - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" + }, + "node_modules/fast-xml-builder": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.5.tgz", + "integrity": "sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.1.3" + } }, "node_modules/fast-xml-parser": { "version": "4.5.3", @@ -8182,9 +6043,9 @@ } }, "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "dev": true, "license": "ISC", "peer": true, @@ -8192,20 +6053,6 @@ "reusify": "^1.0.4" } }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", @@ -8236,17 +6083,16 @@ "license": "MIT" }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { @@ -8255,7 +6101,6 @@ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -8263,52 +6108,12 @@ "node": ">=8" } }, - "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -8320,40 +6125,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "bin": { - "flat": "cli.js" - } - }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/floating-vue": { "version": "1.0.0-beta.19", @@ -8418,7 +6209,6 @@ "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "is-callable": "^1.2.7" }, @@ -8457,36 +6247,36 @@ "node": ">=12.20.0" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "node_modules/fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", "dev": true, "license": "MIT", - "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=14.14" } }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "peer": true, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.6" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC", - "peer": true - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -8496,50 +6286,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/geojson": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/geojson/-/geojson-0.5.0.tgz", @@ -8601,40 +6347,17 @@ "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-tsconfig": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", - "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "node_modules/git-hooks-list": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-4.2.1.tgz", + "integrity": "sha512-WNvqJjOxxs/8ZP9+DWdwWJ7cDsd60NHf39XnD82pDVrKO5q7xfPqpkK6hwEAmBa/ZSEE4IOoR75EzbbIuwGlMw==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + "url": "https://github.com/fisker/git-hooks-list?sponsor=1" } }, "node_modules/gl-matrix": { @@ -8643,35 +6366,12 @@ "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==", "license": "MIT" }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -8679,39 +6379,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "license": "BSD-2-Clause", - "peer": true - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -8726,7 +6393,7 @@ "node": ">=6" } }, - "node_modules/global-modules/node_modules/global-prefix": { + "node_modules/global-prefix": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", @@ -8742,15 +6409,7 @@ "node": ">=6" } }, - "node_modules/global-modules/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/global-modules/node_modules/which": { + "node_modules/global-prefix/node_modules/which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", @@ -8764,41 +6423,6 @@ "which": "bin/which" } }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -8845,16 +6469,8 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC", - "peer": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true, - "license": "MIT", - "peer": true + "license": "ISC" }, "node_modules/grid-index": { "version": "1.1.0", @@ -8862,34 +6478,12 @@ "integrity": "sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==", "license": "ISC" }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -8900,7 +6494,6 @@ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "es-define-property": "^1.0.0" }, @@ -8908,23 +6501,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -8958,7 +6534,6 @@ "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1" @@ -8967,24 +6542,31 @@ "node": ">= 0.10" } }, - "node_modules/hash-sum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", - "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", - "license": "MIT" - }, "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" } }, + "node_modules/hashery": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz", + "integrity": "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "hookified": "^1.15.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -9060,6 +6642,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, "node_modules/highlight.js": { "version": "11.11.1", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", @@ -9075,7 +6667,6 @@ "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -9083,9 +6674,9 @@ } }, "node_modules/hookified": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.10.0.tgz", - "integrity": "sha512-dJw0492Iddsj56U1JsSTm9E/0B/29a1AuoSLRAte8vQg/kaTGF3IgjEWT8c8yG4cC10+HisE1x5QAwR0Xwc+DA==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", + "integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==", "dev": true, "license": "MIT", "peer": true @@ -9096,215 +6687,64 @@ "integrity": "sha512-ECg1JFG0YzehicQaogenlcs2qg6WsXQsxtnbr1i696u5tLUjtJdQAh0u2g0Q5YV45f263Ta1GnUJsc8WIfJf4Q==", "license": "MIT" }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-tags": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", "dev": true, "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", - "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-middleware": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", - "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" } - } + ], + "license": "MIT" }, - "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", "dev": true, "license": "MIT", "peer": true, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/http-proxy/node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], "license": "MIT", - "peer": true + "peer": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } }, "node_modules/https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/hyperdyperid": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", - "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.18" - } + "license": "MIT" }, "node_modules/i18next": { "version": "24.2.3", @@ -9353,32 +6793,18 @@ "license": "MPL-2.0" }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "peer": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "license": "ISC", - "peer": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -9398,8 +6824,7 @@ "url": "https://feross.org/support" } ], - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/ignore": { "version": "5.3.2", @@ -9407,18 +6832,16 @@ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 4" } }, "node_modules/immutable": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", - "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/import-fresh": { "version": "3.3.1", @@ -9438,25 +6861,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", "peer": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true, + "license": "MIT", "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/imurmurhash": { @@ -9465,28 +6888,22 @@ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, "license": "ISC", "peer": true }, @@ -9496,53 +6913,16 @@ "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==", "license": "MIT" }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", "peer": true, "engines": { "node": ">=12" } }, - "node_modules/interpret": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", - "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 10" - } - }, "node_modules/is-absolute-url": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", @@ -9561,7 +6941,6 @@ "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" @@ -9573,25 +6952,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -9600,167 +6960,18 @@ "license": "MIT", "peer": true }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "has-bigints": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "license": "MIT" }, - "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==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-bun-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", - "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "semver": "^7.7.1" - } - }, - "node_modules/is-bun-module/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, "engines": { "node": ">= 0.4" }, @@ -9768,16 +6979,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -9786,51 +6995,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -9848,7 +7022,6 @@ "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", @@ -9868,7 +7041,6 @@ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -9876,47 +7048,12 @@ "node": ">=0.10.0" } }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-nan": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.0", "define-properties": "^1.1.3" @@ -9928,74 +7065,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-network-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", - "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.12.0" } }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -10023,7 +7102,6 @@ "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", @@ -10037,37 +7115,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-standalone-pwa": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-standalone-pwa/-/is-standalone-pwa-0.1.1.tgz", @@ -10088,24 +7135,6 @@ ], "license": "MIT" }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-svg": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-6.1.0.tgz", @@ -10121,32 +7150,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-typed-array": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "which-typed-array": "^1.1.16" }, @@ -10157,134 +7166,41 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-wsl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-inside-container": "^1.0.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "node_modules/isomorphic-timers-promises": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-timers-promises/-/isomorphic-timers-promises-1.0.1.tgz", + "integrity": "sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==", "dev": true, "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true, + "license": "MIT" + }, "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", "dev": true, "license": "MIT", "peer": true @@ -10294,6 +7210,7 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "argparse": "^2.0.1" @@ -10303,28 +7220,13 @@ } }, "node_modules/jsdoc-type-pratt-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", - "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.2.0.tgz", + "integrity": "sha512-dh140MMgjyg3JhJZY/+iEzW+NO5xR2gpbDFKHqotCmexElVntw7GjWjt511+C/Ef02RU5TKYrJo/Xlzk+OLaTw==", "dev": true, "license": "MIT", - "peer": true, - "bin": { - "jsesc": "bin/jsesc" - }, "engines": { - "node": ">=6" + "node": ">=20.0.0" } }, "node_modules/json-buffer": { @@ -10332,13 +7234,13 @@ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, "license": "MIT", "peer": true }, @@ -10347,16 +7249,14 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/json-stringify-pretty-compact": { "version": "4.0.0", @@ -10364,18 +7264,17 @@ "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==", "license": "MIT" }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", "dev": true, "license": "MIT", - "peer": true, - "bin": { - "json5": "lib/cli.js" + "dependencies": { + "universalify": "^2.0.0" }, - "engines": { - "node": ">=6" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, "node_modules/kdbush": { @@ -10390,7 +7289,6 @@ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "json-buffer": "3.0.1" } @@ -10414,17 +7312,12 @@ "license": "MIT", "peer": true }, - "node_modules/launch-editor": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.10.0.tgz", - "integrity": "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==", + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "picocolors": "^1.0.0", - "shell-quote": "^1.8.1" - } + "license": "MIT" }, "node_modules/layerr": { "version": "3.0.0", @@ -10519,7 +7412,6 @@ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -10546,46 +7438,28 @@ } }, "node_modules/linkifyjs": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.1.tgz", - "integrity": "sha512-DRSlB9DKVW04c4SUdGvKK5FR6be45lTU9M76JnngqPeeGDqPwYc0zdUErtsNVMtxPXgUWV4HbXbnC4sNyBxkYg==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.2.tgz", + "integrity": "sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==", "license": "MIT", "peer": true }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "dev": true, "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" }, "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/loader-utils/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" + "node": ">=14" }, - "bin": { - "json5": "lib/cli.js" + "funding": { + "url": "https://github.com/sponsors/antfu" } }, "node_modules/locate-path": { @@ -10594,7 +7468,6 @@ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -10610,24 +7483,7 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lodash.throttle": { "version": "4.1.1", @@ -10668,14 +7524,14 @@ "polyline": "0.0.3" } }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "yallist": "^3.0.2" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, "node_modules/mapbox-gl": { @@ -10826,7 +7682,6 @@ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -10948,52 +7803,19 @@ } }, "node_modules/mdn-data": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", - "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", "dev": true, "license": "CC0-1.0", "peer": true }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memfs": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.17.2.tgz", - "integrity": "sha512-NgYhCOWgovOXSzvYgUW0LQ7Qy72rWQMGGFJDoWg4G30RHd3z77VbYdtJ4fembJXBy8pMIUA31XNAupobOQlwdg==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jsonjoy.com/json-pack": "^1.0.3", - "@jsonjoy.com/util": "^1.3.0", - "tree-dump": "^1.0.1", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">= 4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - } - }, "node_modules/meow": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -11001,42 +7823,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "dev": true, - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "license": "MIT", - "dependencies": { - "source-map": "^0.6.1" - } - }, - "node_modules/merge-source-map/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT", - "peer": true - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -11048,17 +7834,6 @@ "node": ">= 8" } }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/micromark": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", @@ -11507,7 +8282,6 @@ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -11522,7 +8296,6 @@ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.0.0", "brorand": "^1.0.1" @@ -11536,22 +8309,7 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } + "license": "MIT" }, "node_modules/mime-db": { "version": "1.52.0", @@ -11579,16 +8337,14 @@ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/minimatch": { "version": "9.0.5", @@ -11614,6 +8370,38 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -11629,20 +8417,12 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } + "license": "MIT" }, "node_modules/murmurhash-js": { "version": "1.0.0", @@ -11668,49 +8448,23 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/napi-postinstall": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.0.tgz", - "integrity": "sha512-M7NqKyhODKV1gRLdkwE7pDsZP2/SC2a2vHkOYh9MCpKMbWVfyVfUw5MaH83Fv6XMjxr5jryUp3IDDL9rlxsTeA==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "napi-postinstall": "lib/cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/napi-postinstall" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, - "node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "node_modules/natural-orderby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-5.0.0.tgz", + "integrity": "sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==", "dev": true, "license": "MIT", - "peer": true, "engines": { - "node": ">= 0.6" + "node": ">=18" } }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "license": "MIT", - "peer": true - }, "node_modules/nested-property": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/nested-property/-/nested-property-4.0.0.tgz", @@ -11723,8 +8477,7 @@ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "dev": true, "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/node-domexception": { "version": "1.0.0", @@ -11745,77 +8498,125 @@ "node": ">=10.5.0" } }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "node_modules/node-releases": { + "version": "2.0.38", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.38.tgz", + "integrity": "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==", "dev": true, - "license": "(BSD-3-Clause OR GPL-2.0)", - "peer": true, - "engines": { - "node": ">= 6.13.0" - } + "license": "MIT" }, - "node_modules/node-polyfill-webpack-plugin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-4.0.0.tgz", - "integrity": "sha512-WLk77vLpbcpmTekRj6s6vYxk30XoyaY5MDZ4+9g8OaKoG3Ij+TjOqhpQjVUlfDZBPBgpNATDltaQkzuXSnnkwg==", + "node_modules/node-stdlib-browser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-stdlib-browser/-/node-stdlib-browser-1.3.1.tgz", + "integrity": "sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "assert": "^2.1.0", + "assert": "^2.0.0", + "browser-resolve": "^2.0.0", "browserify-zlib": "^0.2.0", - "buffer": "^6.0.3", - "console-browserify": "^1.2.0", + "buffer": "^5.7.1", + "console-browserify": "^1.1.0", "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.12.0", - "domain-browser": "^5.7.0", - "events": "^3.3.0", + "create-require": "^1.1.1", + "crypto-browserify": "^3.12.1", + "domain-browser": "4.22.0", + "events": "^3.0.0", "https-browserify": "^1.0.0", + "isomorphic-timers-promises": "^1.0.1", "os-browserify": "^0.3.0", "path-browserify": "^1.0.1", + "pkg-dir": "^5.0.0", "process": "^0.11.10", - "punycode": "^2.3.1", + "punycode": "^1.4.1", "querystring-es3": "^0.2.1", - "readable-stream": "^4.5.2", + "readable-stream": "^3.6.0", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", - "string_decoder": "^1.3.0", - "timers-browserify": "^2.0.12", - "tty-browserify": "^0.0.1", - "type-fest": "^4.18.2", - "url": "^0.11.3", - "util": "^0.12.5", - "vm-browserify": "^1.1.2" + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.1", + "url": "^0.11.4", + "util": "^0.12.4", + "vm-browserify": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-stdlib-browser/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/node-stdlib-browser/node_modules/domain-browser": { + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.22.0.tgz", + "integrity": "sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/node-stdlib-browser/node_modules/pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^5.0.0" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "webpack": ">=5" + "node": ">=10" } }, - "node_modules/node-polyfill-webpack-plugin/node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "node_modules/node-stdlib-browser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "dev": true, - "license": "(MIT OR CC0-1.0)", - "peer": true, - "engines": { - "node": ">=16" + "license": "MIT" + }, + "node_modules/node-stdlib-browser/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 6" } }, - "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "license": "MIT" - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -11839,7 +8640,6 @@ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "boolbase": "^1.0.0" }, @@ -11847,13 +8647,19 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/object-deep-merge": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/object-deep-merge/-/object-deep-merge-2.0.0.tgz", + "integrity": "sha512-3DC3UMpeffLTHiuXSy/UG4NOIYTLlY9u3V82+djSCLYClWobZiS4ivYzpIUWrRY/nfsJ8cWsKyG3QfyLePmhvg==", + "dev": true, + "license": "MIT" + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -11867,7 +8673,6 @@ "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1" @@ -11885,7 +8690,6 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" } @@ -11896,7 +8700,6 @@ "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -11912,125 +8715,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", - "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", - "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/open": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", - "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "default-browser": "^5.2.1", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "wsl-utils": "^0.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/open-location-code": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/open-location-code/-/open-location-code-1.0.3.tgz", @@ -12058,7 +8742,6 @@ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -12076,8 +8759,7 @@ "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/osrm-text-instructions": { "version": "0.13.4", @@ -12085,32 +8767,12 @@ "integrity": "sha512-ge4ZTIetMQKAHKq2MwWf83ntzdJN20ndRKRaVNoZ3SkDkBNO99Qddz7r6+hrVx38I+ih6Rk5T1yslczAB6Q9Pg==", "license": "BSD-2-Clause" }, - "node_modules/own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -12127,7 +8789,6 @@ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -12154,25 +8815,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-retry": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", - "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/retry": "0.12.2", - "is-network-error": "^1.0.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-timeout": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", @@ -12185,15 +8827,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "node_modules/package-name-regex": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/package-name-regex/-/package-name-regex-2.0.6.tgz", + "integrity": "sha512-gFL35q7kbE/zBaPA3UKhp2vSzcPYx2ecbYuwv1ucE9Il6IIgBDweBlH8D68UFGZic2MkllKa2KHCfC1IQBQUYA==", "dev": true, "license": "MIT", - "peer": true, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/dword-design" } }, "node_modules/pako": { @@ -12201,8 +8845,7 @@ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true, - "license": "(MIT AND Zlib)", - "peer": true + "license": "(MIT AND Zlib)" }, "node_modules/parent-module": { "version": "1.0.1", @@ -12224,7 +8867,6 @@ "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "asn1.js": "^4.10.1", "browserify-aes": "^1.2.0", @@ -12237,6 +8879,16 @@ "node": ">= 0.10" } }, + "node_modules/parse-imports-exports": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", + "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-statements": "1.0.11" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -12257,24 +8909,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "node_modules/parse-statements": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", + "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } + "license": "MIT" }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/path-exists": { "version": "4.0.0", @@ -12282,20 +8929,24 @@ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "node_modules/path-expression-matcher": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], "license": "MIT", - "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">=14.0.0" } }, "node_modules/path-key": { @@ -12304,7 +8955,6 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -12314,8 +8964,7 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/path-posix": { "version": "1.0.0", @@ -12323,14 +8972,6 @@ "integrity": "sha512-1gJ0WpNIiYcQydgg3Ed8KzvIqTsDpNwq+cjBCssvBtuTWjEqY1AW+i+OepiEMqDCzyro9B2sLAe4RBPajMYFiA==", "license": "ISC" }, - "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -12342,6 +8983,13 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/pbf": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.1.tgz", @@ -12360,7 +9008,6 @@ "integrity": "sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "create-hash": "~1.1.3", "create-hmac": "^1.1.7", @@ -12379,7 +9026,6 @@ "integrity": "sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -12393,7 +9039,6 @@ "integrity": "sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.1" } @@ -12404,7 +9049,6 @@ "integrity": "sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "hash-base": "^2.0.0", "inherits": "^2.0.1" @@ -12422,7 +9066,6 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8.6" }, @@ -12430,78 +9073,16 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/pkg-types": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", + "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" + "confbox": "^0.2.4", + "exsolve": "^1.0.8", + "pathe": "^2.0.3" } }, "node_modules/pmtiles": { @@ -12527,7 +9108,6 @@ "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" } @@ -12561,9 +9141,9 @@ } }, "node_modules/postcss-html": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.8.0.tgz", - "integrity": "sha512-5mMeb1TgLWoRKxZ0Xh9RZDfwUUIqRrcxO2uXO+Ezl1N5lqpCiSU5Gk6+1kZediBfBHFtPCdopr2UZ2SgUsKcgQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-1.8.1.tgz", + "integrity": "sha512-OLF6P7qctfAWayOhLpcVnTGqVeJzu2W3WpIYelfz2+JV5oGxfkcEvweN9U4XpeqE0P98dcD9ssusGwlF0TK0uQ==", "dev": true, "license": "MIT", "peer": true, @@ -12577,14 +9157,6 @@ "node": "^12 || >=14" } }, - "node_modules/postcss-html/node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/postcss-media-query-parser": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", @@ -12593,97 +9165,6 @@ "license": "MIT", "peer": true }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", - "license": "ISC", - "peer": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", - "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", - "license": "MIT", - "peer": true, - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^7.0.0", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", - "license": "MIT", - "peer": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", - "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", - "license": "ISC", - "peer": true, - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", - "license": "MIT", - "peer": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "license": "ISC", - "peer": true, - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "node_modules/postcss-resolve-nested-selector": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz", @@ -12739,9 +9220,10 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -12755,6 +9237,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, "license": "MIT", "peer": true }, @@ -12770,7 +9253,6 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8.0" } @@ -12797,7 +9279,6 @@ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6.0" } @@ -12807,8 +9288,7 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/property-information": { "version": "6.5.0", @@ -12826,51 +9306,18 @@ "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==", "license": "MIT" }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "license": "MIT" }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "license": "ISC" - }, "node_modules/public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", @@ -12885,8 +9332,7 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/punycode": { "version": "2.3.1", @@ -12894,18 +9340,38 @@ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } }, + "node_modules/qified": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/qified/-/qified-0.9.1.tgz", + "integrity": "sha512-n7mar4T0xQ+39dE2vGTAlbxUEpndwPANH0kDef1/MYsB8Bba9wshkybIRx74qgcvKQPEWErf9AqAdYjhzY2Ilg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "hookified": "^2.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/qified/node_modules/hookified": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz", + "integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/qs": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "side-channel": "^1.1.0" }, @@ -12916,12 +9382,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, "node_modules/querystring-es3": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", "dev": true, - "peer": true, "engines": { "node": ">=0.4.x" } @@ -12960,224 +9442,39 @@ "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", "license": "ISC" }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/readable-stream": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", - "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/rechoir": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", - "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "resolve": "^1.20.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", - "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpu-core": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", - "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.0", - "regjsgen": "^0.8.0", - "regjsparser": "^0.12.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - }, - "engines": { - "node": ">=4" + "safe-buffer": "^5.1.0" } }, - "node_modules/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "dev": true, "license": "MIT", - "peer": true - }, - "node_modules/regjsparser": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", - "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, "dependencies": { - "jsesc": "~3.0.2" - }, - "bin": { - "regjsparser": "bin/parser" + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, "license": "MIT", - "peer": true, - "bin": { - "jsesc": "bin/jsesc" - }, "engines": { - "node": ">=6" + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/rehype-external-links": { @@ -13398,292 +9695,44 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requireindex": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", - "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.5" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "license": "MIT" - }, - "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-core-module": "^2.16.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/resolve-protobuf-schema": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", - "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", - "license": "MIT", - "dependencies": { - "protocol-buffers-schema": "^3.3.1" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", - "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", - "peer": true - }, - "node_modules/run-applescript": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", - "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "license": "BSD-3-Clause" - }, - "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "peer": true + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/safe-push-apply": { + "node_modules/requires-port": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, + "node_modules/reserved-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/reserved-identifiers/-/reserved-identifiers-1.2.0.tgz", + "integrity": "sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "engines": { "node": ">= 0.4" @@ -13692,348 +9741,330 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, "license": "MIT", - "peer": true + "peer": true, + "engines": { + "node": ">=8" + } }, - "node_modules/sass": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.89.2.tgz", - "integrity": "sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==", + "node_modules/resolve-protobuf-schema": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", + "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "license": "MIT", + "dependencies": { + "protocol-buffers-schema": "^3.3.1" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "license": "MIT", "peer": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "license": "MIT", "dependencies": { - "chokidar": "^4.0.0", - "immutable": "^5.0.2", - "source-map-js": ">=0.6.2 <2.0.0" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "license": "Unlicense", + "peer": true + }, + "node_modules/rollup": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz", + "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" }, "bin": { - "sass": "sass.js" + "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, "optionalDependencies": { - "@parcel/watcher": "^2.4.1" + "@rollup/rollup-android-arm-eabi": "4.60.2", + "@rollup/rollup-android-arm64": "4.60.2", + "@rollup/rollup-darwin-arm64": "4.60.2", + "@rollup/rollup-darwin-x64": "4.60.2", + "@rollup/rollup-freebsd-arm64": "4.60.2", + "@rollup/rollup-freebsd-x64": "4.60.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", + "@rollup/rollup-linux-arm-musleabihf": "4.60.2", + "@rollup/rollup-linux-arm64-gnu": "4.60.2", + "@rollup/rollup-linux-arm64-musl": "4.60.2", + "@rollup/rollup-linux-loong64-gnu": "4.60.2", + "@rollup/rollup-linux-loong64-musl": "4.60.2", + "@rollup/rollup-linux-ppc64-gnu": "4.60.2", + "@rollup/rollup-linux-ppc64-musl": "4.60.2", + "@rollup/rollup-linux-riscv64-gnu": "4.60.2", + "@rollup/rollup-linux-riscv64-musl": "4.60.2", + "@rollup/rollup-linux-s390x-gnu": "4.60.2", + "@rollup/rollup-linux-x64-gnu": "4.60.2", + "@rollup/rollup-linux-x64-musl": "4.60.2", + "@rollup/rollup-openbsd-x64": "4.60.2", + "@rollup/rollup-openharmony-arm64": "4.60.2", + "@rollup/rollup-win32-arm64-msvc": "4.60.2", + "@rollup/rollup-win32-ia32-msvc": "4.60.2", + "@rollup/rollup-win32-x64-gnu": "4.60.2", + "@rollup/rollup-win32-x64-msvc": "4.60.2", + "fsevents": "~2.3.2" } }, - "node_modules/sass-loader": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.5.tgz", - "integrity": "sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==", + "node_modules/rollup-plugin-corejs": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-corejs/-/rollup-plugin-corejs-1.0.2.tgz", + "integrity": "sha512-1IDoQa+EW2NraBc7xANejbQwx62jNikLnDBNrzguRhfVnatyjCcmiIJJ4ScG6PwMP6OIwS8osHMl43CcVJqvaQ==", "dev": true, - "license": "MIT", - "peer": true, + "license": "EUPL-1.2", "dependencies": { - "neo-async": "^2.6.2" + "acorn": "^8.14.0", + "browserslist": "^4.26.3", + "core-js-compat": "^3.46.0", + "estree-toolkit": "^1.7.8", + "magic-string": "^0.30.19" }, "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">= 20.0.0" }, "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", - "sass": "^1.3.0", - "sass-embedded": "*", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "webpack": { - "optional": true - } + "rollup": "^3 || ^4" } }, - "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "license": "ISC" - }, - "node_modules/schema-utils": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", - "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "node_modules/rollup-plugin-esbuild-minify": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-esbuild-minify/-/rollup-plugin-esbuild-minify-1.3.0.tgz", + "integrity": "sha512-y7BDyMMGYhq5901EijNABWgjEzC8myYhOXKmlnU8xIRvX7KQucSWABBR3IEyITuLJFyq/rXIlezDh9zvnR0k2w==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "esbuild": "^0.25.3" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 14.18" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "peerDependencies": { + "rollup": "^2 || ^3 || ^4" } }, - "node_modules/schema-utils/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "node_modules/rollup-plugin-license": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-license/-/rollup-plugin-license-3.7.1.tgz", + "integrity": "sha512-FcGXUbAmPvRSLxjVdjp/r/MUtKBlttVQd+ApUyvKfREnsoAfAZA6Ic2fE1Tz4RL0f9XqEQU9UIRNUMdtQtliDw==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "commenting": "^1.1.0", + "fdir": "^6.4.3", + "lodash": "^4.17.21", + "magic-string": "^0.30.0", + "moment": "^2.30.1", + "package-name-regex": "^2.0.6", + "spdx-expression-validate": "^2.0.0", + "spdx-satisfies": "^5.0.1" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/schema-utils/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" + "engines": { + "node": ">=14.0.0" }, "peerDependencies": { - "ajv": "^8.8.2" + "rollup": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0" } }, - "node_modules/schema-utils/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT", - "peer": true - }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "node_modules/rollup-plugin-license/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", - "peer": true + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } }, - "node_modules/selfsigned": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "node_modules/rollup-plugin-license/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", + "optional": true, "peer": true, - "dependencies": { - "@types/node-forge": "^1.3.0", - "node-forge": "^1" - }, "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "node_modules/rollup-plugin-node-externals": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-externals/-/rollup-plugin-node-externals-8.1.2.tgz", + "integrity": "sha512-EuB6/lolkMLK16gvibUjikERq5fCRVIGwD2xue/CrM8D0pz5GXD2V6N8IrgxegwbcUoKkUFI8VYCEEv8MMvgpA==", "dev": true, + "funding": [ + { + "type": "patreon", + "url": "https://patreon.com/Septh" + }, + { + "type": "paypal", + "url": "https://paypal.me/septh07" + } + ], "license": "MIT", - "peer": true, - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, "engines": { - "node": ">= 0.8.0" + "node": ">= 21 || ^20.6.0 || ^18.19.0" + }, + "peerDependencies": { + "rollup": "^4.0.0" } }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", "peer": true, "dependencies": { - "ms": "2.0.0" + "queue-microtask": "^1.2.2" } }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT", - "peer": true + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" }, - "node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "randombytes": "^2.1.0" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" }, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "2.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/serve-index/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "dev": true, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } + "peer": true }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "node_modules/sass": { + "version": "1.99.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.99.0.tgz", + "integrity": "sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "chokidar": "^4.0.0", + "immutable": "^5.1.5", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" }, "engines": { - "node": ">= 0.6" + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" } }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT", - "peer": true + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "license": "ISC", - "peer": true - }, - "node_modules/serve-index/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">= 0.8.0" + "node": ">=10" } }, "node_modules/set-function-length": { @@ -14042,7 +10073,6 @@ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -14055,54 +10085,12 @@ "node": ">= 0.4" } }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC", - "peer": true + "license": "MIT" }, "node_modules/sha.js": { "version": "2.4.12", @@ -14110,7 +10098,6 @@ "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", "dev": true, "license": "(MIT AND BSD-3-Clause)", - "peer": true, "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1", @@ -14126,27 +10113,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -14160,32 +10132,16 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", @@ -14206,7 +10162,6 @@ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" @@ -14224,7 +10179,6 @@ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -14244,7 +10198,6 @@ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -14303,28 +10256,33 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "node_modules/sort-object-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-2.1.0.tgz", + "integrity": "sha512-SOiEnthkJKPv2L6ec6HMwhUcN0/lppkeYuN1x63PbyPRrgSPIuBJCiYxYyvWRTtjMlOi14vQUCGUJqS6PLVm8g==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } + "license": "MIT" }, - "node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "node_modules/sort-package-json": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-3.6.1.tgz", + "integrity": "sha512-Chgejw1+10p2D0U2tB7au1lHtz6TkFnxmvZktyBCRyV0GgmF6nl1IxXxAsPtJVsUyg/fo+BfCMAVVFUVRkAHrQ==", "dev": true, - "license": "BSD-3-Clause", - "peer": true, + "license": "MIT", + "dependencies": { + "detect-indent": "^7.0.2", + "detect-newline": "^4.0.1", + "git-hooks-list": "^4.1.1", + "is-plain-obj": "^4.1.0", + "semver": "^7.7.3", + "sort-object-keys": "^2.0.1", + "tinyglobby": "^0.2.15" + }, + "bin": { + "sort-package-json": "cli.js" + }, "engines": { - "node": ">= 8" + "node": ">=20" } }, "node_modules/source-map-js": { @@ -14336,27 +10294,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "license": "MIT", - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/space-separated-tokens": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", @@ -14367,13 +10304,35 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/spdx-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", + "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-find-index": "^1.0.2", + "spdx-expression-parse": "^3.0.0", + "spdx-ranges": "^2.0.0" + } + }, + "node_modules/spdx-compare/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/spdx-exceptions": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true, - "license": "CC-BY-3.0", - "peer": true + "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "4.0.0", @@ -14381,7 +10340,27 @@ "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, "license": "MIT", - "peer": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-expression-validate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-validate/-/spdx-expression-validate-2.0.0.tgz", + "integrity": "sha512-b3wydZLM+Tc6CFvaRDBOF9d76oGIHNCLYFeHbftFXUWjnfZWganmDmvtM5sm1cRwJc/VDBMLyGGrsLFd1vOxbg==", + "dev": true, + "license": "(MIT AND CC-BY-3.0)", + "dependencies": { + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/spdx-expression-validate/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -14392,57 +10371,36 @@ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", "dev": true, - "license": "CC0-1.0", - "peer": true + "license": "CC0-1.0" }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "node_modules/spdx-ranges": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", + "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } + "license": "(MIT AND CC-BY-3.0)" }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "node_modules/spdx-satisfies": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-5.0.1.tgz", + "integrity": "sha512-Nwor6W6gzFp8XX4neaKQ7ChV4wmpSh2sSDemMFSzHxpTw460jxFYeOn+jq4ybnSSw/5sc3pjka9MQPouksQNpw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" + "spdx-compare": "^1.0.0", + "spdx-expression-parse": "^3.0.0", + "spdx-ranges": "^2.0.0" } }, - "node_modules/spdy-transport/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/spdx-satisfies/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, "node_modules/splaytree": { @@ -14457,39 +10415,12 @@ "integrity": "sha512-kpEo1WuMXuc6QfdQdO2V/fl/trONlkUKp+pputsLTiW9RMtwEvjb4/aYGm2m3+KAzjmb+zLwr4A4SYZu74+pgQ==", "license": "MIT" }, - "node_modules/stable-hash": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", - "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } + "license": "BSD-3-Clause" }, "node_modules/stream-browserify": { "version": "3.0.0", @@ -14497,7 +10428,6 @@ "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "~2.0.4", "readable-stream": "^3.5.0" @@ -14509,7 +10439,6 @@ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -14525,7 +10454,6 @@ "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "builtin-status-codes": "^3.0.0", "inherits": "^2.0.4", @@ -14539,7 +10467,6 @@ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -14555,9 +10482,18 @@ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "~5.2.0" + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" } }, "node_modules/string-length": { @@ -14619,1598 +10555,1876 @@ "node": ">=8" } }, - "node_modules/string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/striptags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/striptags/-/striptags-3.2.0.tgz", + "integrity": "sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw==", + "license": "MIT" + }, + "node_modules/strnum": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/strtok3": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.1.tgz", + "integrity": "sha512-3JWEZM6mfix/GCJBBUrkA8p2Id2pBkyTkVCJKto55w080QBKZ+8R171fGrbiSp+yMO/u6F8/yUh7K4V9K+YCnw==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/style-to-object": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", + "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, + "node_modules/stylelint": { + "version": "16.26.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.26.1.tgz", + "integrity": "sha512-v20V59/crfc8sVTAtge0mdafI3AdnzQ2KsWe6v523L4OA1bJO02S7MO2oyXDCS6iWb9ckIPnqAFVItqSBQr7jw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-syntax-patches-for-csstree": "^1.0.19", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3", + "@csstools/selector-specificity": "^5.0.0", + "@dual-bundle/import-meta-resolve": "^4.2.1", + "balanced-match": "^2.0.0", + "colord": "^2.9.3", + "cosmiconfig": "^9.0.0", + "css-functions-list": "^3.2.3", + "css-tree": "^3.1.0", + "debug": "^4.4.3", + "fast-glob": "^3.3.3", + "fastest-levenshtein": "^1.0.16", + "file-entry-cache": "^11.1.1", + "global-modules": "^2.0.0", + "globby": "^11.1.0", + "globjoin": "^0.1.4", + "html-tags": "^3.3.1", + "ignore": "^7.0.5", + "imurmurhash": "^0.1.4", + "is-plain-object": "^5.0.0", + "known-css-properties": "^0.37.0", + "mathml-tag-names": "^2.1.3", + "meow": "^13.2.0", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.5.6", + "postcss-resolve-nested-selector": "^0.1.6", + "postcss-safe-parser": "^7.0.1", + "postcss-selector-parser": "^7.1.0", + "postcss-value-parser": "^4.2.0", + "resolve-from": "^5.0.0", + "string-width": "^4.2.3", + "supports-hyperlinks": "^3.2.0", + "svg-tags": "^1.0.0", + "table": "^6.9.0", + "write-file-atomic": "^5.0.1" + }, + "bin": { + "stylelint": "bin/stylelint.mjs" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/stylelint-config-html": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stylelint-config-html/-/stylelint-config-html-1.1.0.tgz", + "integrity": "sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^12 || >=14" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "postcss-html": "^1.0.0", + "stylelint": ">=14.0.0" + } + }, + "node_modules/stylelint-config-recommended": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-16.0.0.tgz", + "integrity": "sha512-4RSmPjQegF34wNcK1e1O3Uz91HN8P1aFdFzio90wNK9mjgAI19u5vsU868cVZboKzCaa5XbpvtTzAAGQAxpcXA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "stylelint": "^16.16.0" + } + }, + "node_modules/stylelint-config-recommended-scss": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-15.0.1.tgz", + "integrity": "sha512-V24bxkNkFGggqPVJlP9iXaBabwSGEG7QTz+PyxrRtjPkcF+/NsWtB3tKYvFYEmczRkWiIEfuFMhGpJFj9Fxe6Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "postcss-scss": "^4.0.9", + "stylelint-config-recommended": "^16.0.0", + "stylelint-scss": "^6.12.0" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "postcss": "^8.3.3", + "stylelint": "^16.16.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + } + } + }, + "node_modules/stylelint-config-recommended-vue": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended-vue/-/stylelint-config-recommended-vue-1.6.1.tgz", + "integrity": "sha512-lLW7hTIMBiTfjenGuDq2kyHA6fBWd/+Df7MO4/AWOxiFeXP9clbpKgg27kHfwA3H7UNMGC7aeP3mNlZB5LMmEQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "semver": "^7.3.5", + "stylelint-config-html": ">=1.0.0", + "stylelint-config-recommended": ">=6.0.0" + }, + "engines": { + "node": "^12 || >=14" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "postcss-html": "^1.0.0", + "stylelint": ">=14.0.0" + } + }, + "node_modules/stylelint-scss": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-6.14.0.tgz", + "integrity": "sha512-ZKmHMZolxeuYsnB+PCYrTpFce0/QWX9i9gh0hPXzp73WjuIMqUpzdQaBCrKoLWh6XtCFSaNDErkMPqdjy1/8aA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "css-tree": "^3.0.1", + "is-plain-object": "^5.0.0", + "known-css-properties": "^0.37.0", + "mdn-data": "^2.25.0", + "postcss-media-query-parser": "^0.2.3", + "postcss-resolve-nested-selector": "^0.1.6", + "postcss-selector-parser": "^7.1.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "stylelint": "^16.8.2" + } + }, + "node_modules/stylelint-use-logical": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/stylelint-use-logical/-/stylelint-use-logical-2.1.2.tgz", + "integrity": "sha512-4ffvPNk/swH4KS3izExWuzQOuzLmi0gb0uOhvxWJ20vDA5W5xKCjcHHtLoAj1kKvTIX6eGIN5xGtaVin9PD0wg==", + "dev": true, + "license": "CC0-1.0", + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "stylelint": ">= 11 < 17" + } + }, + "node_modules/stylelint/node_modules/balanced-match": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", + "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/stylelint/node_modules/file-entry-cache": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.2.tgz", + "integrity": "sha512-N2WFfK12gmrK1c1GXOqiAJ1tc5YE+R53zvQ+t5P8S5XhnmKYVB5eZEiLNZKDSmoG8wqqbF9EXYBBW/nef19log==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flat-cache": "^6.1.20" + } + }, + "node_modules/stylelint/node_modules/flat-cache": { + "version": "6.1.22", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.22.tgz", + "integrity": "sha512-N2dnzVJIphnNsjHcrxGW7DePckJ6haPrSFqpsBUhHYgwtKGVq4JrBGielEGD2fCVnsGm1zlBVZ8wGhkyuetgug==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "cacheable": "^2.3.4", + "flatted": "^3.4.2", + "hookified": "^1.15.0" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "node_modules/stylelint/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, "license": "MIT", "peer": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 4" } }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "node_modules/stylelint/node_modules/postcss-safe-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "peer": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, "engines": { - "node": ">= 0.4" + "node": ">=18.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "postcss": "^8.4.31" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/suncalc": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/suncalc/-/suncalc-1.9.0.tgz", + "integrity": "sha512-vMJ8Byp1uIPoj+wb9c1AdK4jpkSKVAywgHX0lqY7zt6+EWRRC3Z+0Ucfjy/0yxTVO1hwwchZe4uoFNqrIC24+A==" + }, + "node_modules/supercluster": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", + "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", + "license": "ISC", + "dependencies": { + "kdbush": "^4.0.2" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "ansi-regex": "^5.0.1" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", "dev": true, "license": "MIT", "peer": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, "engines": { - "node": ">=4" + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, "license": "MIT", - "peer": true, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/striptags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/striptags/-/striptags-3.2.0.tgz", - "integrity": "sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw==", - "license": "MIT" + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true, + "peer": true }, - "node_modules/strnum": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", - "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", "license": "MIT" }, - "node_modules/strtok3": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.1.tgz", - "integrity": "sha512-3JWEZM6mfix/GCJBBUrkA8p2Id2pBkyTkVCJKto55w080QBKZ+8R171fGrbiSp+yMO/u6F8/yUh7K4V9K+YCnw==", - "license": "MIT", + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, "dependencies": { - "@tokenizer/token": "^0.3.0" + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" + "node": ">=10.0.0" } }, - "node_modules/style-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", - "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", + "node_modules/table/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "peer": true, - "engines": { - "node": ">= 18.12.0" + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.27.0" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/style-to-object": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", - "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, "license": "MIT", - "dependencies": { - "inline-style-parser": "0.1.1" - } + "peer": true }, - "node_modules/stylelint": { - "version": "16.21.1", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.21.1.tgz", - "integrity": "sha512-WCXdXnYK2tpCbebgMF0Bme3YZH/Rh/UXerj75twYo4uLULlcrLwFVdZTvTEF8idFnAcW21YUDJFyKOfaf6xJRw==", + "node_modules/timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/stylelint" - }, - { - "type": "github", - "url": "https://github.com/sponsors/stylelint" - } - ], "license": "MIT", - "peer": true, "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "@csstools/media-query-list-parser": "^4.0.3", - "@csstools/selector-specificity": "^5.0.0", - "@dual-bundle/import-meta-resolve": "^4.1.0", - "balanced-match": "^2.0.0", - "colord": "^2.9.3", - "cosmiconfig": "^9.0.0", - "css-functions-list": "^3.2.3", - "css-tree": "^3.1.0", - "debug": "^4.4.1", - "fast-glob": "^3.3.3", - "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^10.1.1", - "global-modules": "^2.0.0", - "globby": "^11.1.0", - "globjoin": "^0.1.4", - "html-tags": "^3.3.1", - "ignore": "^7.0.5", - "imurmurhash": "^0.1.4", - "is-plain-object": "^5.0.0", - "known-css-properties": "^0.37.0", - "mathml-tag-names": "^2.1.3", - "meow": "^13.2.0", - "micromatch": "^4.0.8", - "normalize-path": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.5.6", - "postcss-resolve-nested-selector": "^0.1.6", - "postcss-safe-parser": "^7.0.1", - "postcss-selector-parser": "^7.1.0", - "postcss-value-parser": "^4.2.0", - "resolve-from": "^5.0.0", - "string-width": "^4.2.3", - "supports-hyperlinks": "^3.2.0", - "svg-tags": "^1.0.0", - "table": "^6.9.0", - "write-file-atomic": "^5.0.1" - }, - "bin": { - "stylelint": "bin/stylelint.mjs" + "setimmediate": "^1.0.4" }, "engines": { - "node": ">=18.12.0" - } - }, - "node_modules/stylelint-config-html": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stylelint-config-html/-/stylelint-config-html-1.1.0.tgz", - "integrity": "sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^12 || >=14" - }, - "funding": { - "url": "https://github.com/sponsors/ota-meshi" - }, - "peerDependencies": { - "postcss-html": "^1.0.0", - "stylelint": ">=14.0.0" + "node": ">=0.6.0" } }, - "node_modules/stylelint-config-recommended": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-16.0.0.tgz", - "integrity": "sha512-4RSmPjQegF34wNcK1e1O3Uz91HN8P1aFdFzio90wNK9mjgAI19u5vsU868cVZboKzCaa5XbpvtTzAAGQAxpcXA==", + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/stylelint" - }, - { - "type": "github", - "url": "https://github.com/sponsors/stylelint" - } - ], "license": "MIT", - "peer": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, "engines": { - "node": ">=18.12.0" + "node": ">=12.0.0" }, - "peerDependencies": { - "stylelint": "^16.16.0" + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/stylelint-config-recommended-scss": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-15.0.1.tgz", - "integrity": "sha512-V24bxkNkFGggqPVJlP9iXaBabwSGEG7QTz+PyxrRtjPkcF+/NsWtB3tKYvFYEmczRkWiIEfuFMhGpJFj9Fxe6Q==", + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "postcss-scss": "^4.0.9", - "stylelint-config-recommended": "^16.0.0", - "stylelint-scss": "^6.12.0" - }, "engines": { - "node": ">=20" + "node": ">=12.0.0" }, "peerDependencies": { - "postcss": "^8.3.3", - "stylelint": "^16.16.0" + "picomatch": "^3 || ^4" }, "peerDependenciesMeta": { - "postcss": { + "picomatch": { "optional": true } } }, - "node_modules/stylelint-config-recommended-vue": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended-vue/-/stylelint-config-recommended-vue-1.6.1.tgz", - "integrity": "sha512-lLW7hTIMBiTfjenGuDq2kyHA6fBWd/+Df7MO4/AWOxiFeXP9clbpKgg27kHfwA3H7UNMGC7aeP3mNlZB5LMmEQ==", + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "semver": "^7.3.5", - "stylelint-config-html": ">=1.0.0", - "stylelint-config-recommended": ">=6.0.0" - }, "engines": { - "node": "^12 || >=14" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ota-meshi" - }, - "peerDependencies": { - "postcss-html": "^1.0.0", - "stylelint": ">=14.0.0" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/stylelint-config-recommended-vue/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } + "node_modules/tinyqueue": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", + "license": "ISC" }, - "node_modules/stylelint-scss": { - "version": "6.12.1", - "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-6.12.1.tgz", - "integrity": "sha512-UJUfBFIvXfly8WKIgmqfmkGKPilKB4L5j38JfsDd+OCg2GBdU0vGUV08Uw82tsRZzd4TbsUURVVNGeOhJVF7pA==", + "node_modules/to-buffer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz", + "integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "css-tree": "^3.0.1", - "is-plain-object": "^5.0.0", - "known-css-properties": "^0.36.0", - "mdn-data": "^2.21.0", - "postcss-media-query-parser": "^0.2.3", - "postcss-resolve-nested-selector": "^0.1.6", - "postcss-selector-parser": "^7.1.0", - "postcss-value-parser": "^4.2.0" + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" }, "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "stylelint": "^16.0.2" + "node": ">= 0.4" } }, - "node_modules/stylelint-scss/node_modules/known-css-properties": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.36.0.tgz", - "integrity": "sha512-A+9jP+IUmuQsNdsLdcg6Yt7voiMF/D4K83ew0OpJtpu+l34ef7LaohWV0Rc6KNvzw6ZDizkqfyB5JznZnzuKQA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/stylelint-scss/node_modules/mdn-data": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.22.1.tgz", - "integrity": "sha512-u9Xnc9zLuF/CL2IHPow7HcXPpb8okQyzYpwL5wFsY//JRedSWYglYRg3PYWoQCu1zO+tBTmWOJN/iM0mPC5CRQ==", - "dev": true, - "license": "CC0-1.0", - "peer": true - }, - "node_modules/stylelint-scss/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" + "is-number": "^7.0.0" }, "engines": { - "node": ">=4" + "node": ">=8.0" } }, - "node_modules/stylelint-use-logical": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/stylelint-use-logical/-/stylelint-use-logical-2.1.2.tgz", - "integrity": "sha512-4ffvPNk/swH4KS3izExWuzQOuzLmi0gb0uOhvxWJ20vDA5W5xKCjcHHtLoAj1kKvTIX6eGIN5xGtaVin9PD0wg==", + "node_modules/to-valid-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-valid-identifier/-/to-valid-identifier-1.0.0.tgz", + "integrity": "sha512-41wJyvKep3yT2tyPqX/4blcfybknGB4D+oETKLs7Q76UiPqRpUJK3hr1nxelyYO0PHKVzJwlu0aCeEAsGI6rpw==", "dev": true, - "license": "CC0-1.0", - "engines": { - "node": ">=14.0.0" + "license": "MIT", + "dependencies": { + "@sindresorhus/base62": "^1.0.0", + "reserved-identifiers": "^1.0.0" }, - "peerDependencies": { - "stylelint": ">= 11 < 17" - } - }, - "node_modules/stylelint/node_modules/@csstools/selector-specificity": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", - "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "peer": true, "engines": { - "node": ">=18" + "node": ">=20" }, - "peerDependencies": { - "postcss-selector-parser": "^7.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/stylelint/node_modules/balanced-match": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", - "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", - "dev": true, - "license": "MIT", - "peer": true + "node_modules/toastify-js": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.12.0.tgz", + "integrity": "sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ==", + "license": "MIT" }, - "node_modules/stylelint/node_modules/file-entry-cache": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-10.1.1.tgz", - "integrity": "sha512-zcmsHjg2B2zjuBgjdnB+9q0+cWcgWfykIcsDkWDB4GTPtl1eXUA+gTI6sO0u01AqK3cliHryTU55/b2Ow1hfZg==", - "dev": true, + "node_modules/tributejs": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/tributejs/-/tributejs-5.1.3.tgz", + "integrity": "sha512-B5CXihaVzXw+1UHhNFyAwUTMDk1EfoLP5Tj1VhD9yybZ1I8DZJEv8tZ1l0RJo0t0tk9ZhR8eG5tEsaCvRigmdQ==", + "license": "MIT" + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", "license": "MIT", - "peer": true, - "dependencies": { - "flat-cache": "^6.1.10" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/stylelint/node_modules/flat-cache": { - "version": "6.1.11", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.11.tgz", - "integrity": "sha512-zfOAns94mp7bHG/vCn9Ru2eDCmIxVQ5dELUHKjHfDEOJmHNzE+uGa6208kfkgmtym4a0FFjEuFksCXFacbVhSg==", - "dev": true, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", "license": "MIT", - "peer": true, - "dependencies": { - "cacheable": "^1.10.1", - "flatted": "^3.3.3", - "hookified": "^1.10.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/stylelint/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "node_modules/tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", - "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, "engines": { - "node": ">= 4" + "node": ">= 0.8.0" } }, - "node_modules/stylelint/node_modules/postcss-safe-parser": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", - "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", - "peer": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, "engines": { - "node": ">=18.0" + "node": ">= 0.4" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, - "peerDependencies": { - "postcss": "^8.4.31" + "engines": { + "node": ">=14.17" } }, - "node_modules/stylelint/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/typescript-eslint": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.1.tgz", + "integrity": "sha512-xqDcFVBmlrltH64lklOVp1wYxgJr6LVdg3NamBgH2OOQDLFdTKfIZXF5PfghrnXQKXZGTQs8tr1vL7fJvq8CTQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" + "@typescript-eslint/eslint-plugin": "8.59.1", + "@typescript-eslint/parser": "8.59.1", + "@typescript-eslint/typescript-estree": "8.59.1", + "@typescript-eslint/utils": "8.59.1" }, "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/stylelint/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.1.tgz", + "integrity": "sha512-BOziFIfE+6osHO9FoJG4zjoHUcvI7fTNBSpdAwrNH0/TLvzjsk2oo8XSSOT2HhqUyhZPfHv4UOffoJ9oEEQ7Ag==", "dev": true, "license": "MIT", - "peer": true, + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.59.1", + "@typescript-eslint/type-utils": "8.59.1", + "@typescript-eslint/utils": "8.59.1", + "@typescript-eslint/visitor-keys": "8.59.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.59.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/suncalc": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/suncalc/-/suncalc-1.9.0.tgz", - "integrity": "sha512-vMJ8Byp1uIPoj+wb9c1AdK4jpkSKVAywgHX0lqY7zt6+EWRRC3Z+0Ucfjy/0yxTVO1hwwchZe4uoFNqrIC24+A==" - }, - "node_modules/supercluster": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", - "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", - "license": "ISC", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.1.tgz", + "integrity": "sha512-HDQH9O/47Dxi1ceDhBXdaldtf/WV9yRYMjbjCuNk3qnaTD564qwv61Y7+gTxwxRKzSrgO5uhtw584igXVuuZkA==", + "dev": true, + "license": "MIT", "dependencies": { - "kdbush": "^4.0.2" + "@typescript-eslint/scope-manager": "8.59.1", + "@typescript-eslint/types": "8.59.1", + "@typescript-eslint/typescript-estree": "8.59.1", + "@typescript-eslint/visitor-keys": "8.59.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.1.tgz", + "integrity": "sha512-LwuHQI4pDOYVKvmH2dkaJo6YZCSgouVgnS/z7yBPKBMvgtBvyLqiLy9Z6b7+m/TRcX1NFYUqZetI5Y+aT4GEfg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "has-flag": "^4.0.0" + "@typescript-eslint/types": "8.59.1", + "@typescript-eslint/visitor-keys": "8.59.1" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/supports-hyperlinks": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", - "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.1.tgz", + "integrity": "sha512-klWPBR2ciQHS3f++ug/mVnWKPjBUo7icEL3FAO1lhAR1Z1i5NQYZ1EannMSRYcq5qCv5wNALlXr6fksRHyYl7w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" + "@typescript-eslint/types": "8.59.1", + "@typescript-eslint/typescript-estree": "8.59.1", + "@typescript-eslint/utils": "8.59.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": ">=14.18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.1.tgz", + "integrity": "sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==", "dev": true, "license": "MIT", - "peer": true, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/svg-tags": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", - "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", - "dev": true, - "peer": true - }, - "node_modules/tabbable": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", - "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", - "license": "MIT" - }, - "node_modules/table": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", - "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.1.tgz", + "integrity": "sha512-OUd+vJS05sSkOip+BkZ/2NS8RMxrAAJemsC6vU3kmfLyeaJT0TftHkV9mcx2107MmsBVXXexhVu4F0TZXyMl4g==", "dev": true, - "license": "BSD-3-Clause", - "peer": true, + "license": "MIT", "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" + "@typescript-eslint/project-service": "8.59.1", + "@typescript-eslint/tsconfig-utils": "8.59.1", + "@typescript-eslint/types": "8.59.1", + "@typescript-eslint/visitor-keys": "8.59.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": ">=10.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/table/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.1.tgz", + "integrity": "sha512-3pIeoXhCeYH9FSCBI8P3iNwJlGuzPlYKkTlen2O9T1DSeeg8UG8jstq6BLk+Mda0qup7mgk4z4XL4OzRaxZ8LA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.59.1", + "@typescript-eslint/types": "8.59.1", + "@typescript-eslint/typescript-estree": "8.59.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.1.tgz", + "integrity": "sha512-LdDNl6C5iJExcM0Yh0PwAIBb9PrSiCsWamF/JyEZawm3kFDnRoaq3LGE4bpyRao/fWeGKKyw7icx0YxrLFC5Cg==", "dev": true, "license": "MIT", - "peer": true + "dependencies": { + "@typescript-eslint/types": "8.59.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } }, - "node_modules/tapable": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", - "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", + "node_modules/typescript-eslint/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, "license": "MIT", - "peer": true, "engines": { - "node": ">=6" + "node": "18 || 20 || >=22" } }, - "node_modules/terser": { - "version": "5.43.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", - "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", - "license": "BSD-2-Clause", - "peer": true, + "node_modules/typescript-eslint/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.14.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">=10" + "node": "18 || 20 || >=22" } }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.14", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", - "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "node_modules/typescript-eslint/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, "license": "MIT", - "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/typescript-eslint/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "jest-worker": "^27.4.5", - "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", - "terser": "^5.31.1" + "brace-expansion": "^5.0.5" }, "engines": { - "node": ">= 10.13.0" + "node": "18 || 20 || >=22" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "node_modules/typescript-eslint/node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, "license": "MIT", - "peer": true - }, - "node_modules/thingies": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", - "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", - "dev": true, - "license": "Unlicense", - "peer": true, "engines": { - "node": ">=10.18" + "node": ">=18.12" }, "peerDependencies": { - "tslib": "^2" + "typescript": ">=4.8.4" } }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true, - "license": "MIT", - "peer": true + "node_modules/typescript-event-target": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/typescript-event-target/-/typescript-event-target-1.1.1.tgz", + "integrity": "sha512-dFSOFBKV6uwaloBCCUhxlD3Pr/P1a/tJdcmPrTXCHlEFD3faj0mztjcGn6VBAhQ0/Bdy8K3VWrrqwbt/ffsYsg==", + "license": "MIT" }, - "node_modules/timers-browserify": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", - "dev": true, - "license": "MIT", - "peer": true, + "node_modules/ua-is-frozen": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ua-is-frozen/-/ua-is-frozen-0.1.2.tgz", + "integrity": "sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "license": "MIT" + }, + "node_modules/ua-parser-js": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-2.0.5.tgz", + "integrity": "sha512-sZErtx3rhpvZQanWW5umau4o/snfoLqRcQwQIZ54377WtRzIecnIKvjpkd5JwPcSUMglGnbIgcsQBGAbdi3S9Q==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], "dependencies": { - "setimmediate": "^1.0.4" + "detect-europe-js": "^0.1.2", + "is-standalone-pwa": "^0.1.1", + "ua-is-frozen": "^0.1.2", + "undici": "^7.12.0" }, + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.16.0.tgz", + "integrity": "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==", "engines": { - "node": ">=0.6.0" + "node": ">=20.18.1" } }, - "node_modules/tinycolor2": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", - "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", - "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", - "dev": true, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", "license": "MIT", - "peer": true, "dependencies": { - "fdir": "^6.4.4", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" }, "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", - "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", - "dev": true, + "node_modules/unist-builder": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-4.0.0.tgz", + "integrity": "sha512-wmRFnH+BLpZnTKpc5L7O67Kac89s9HMrtELpnNaE6TAobq5DTZZs5YaTQfAZBA9bFPECx2uVAPO31c+GVug8mg==", "license": "MIT", - "peer": true, - "peerDependencies": { - "picomatch": "^3 || ^4" + "dependencies": { + "@types/unist": "^3.0.0" }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, + "node_modules/unist-util-find-after": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/tinyqueue": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", - "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", - "license": "ISC" - }, - "node_modules/to-buffer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz", - "integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==", - "dev": true, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", "license": "MIT", - "peer": true, "dependencies": { - "isarray": "^2.0.5", - "safe-buffer": "^5.2.1", - "typed-array-buffer": "^1.0.3" + "@types/unist": "^3.0.0" }, - "engines": { - "node": ">= 0.4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", "license": "MIT", - "peer": true, "dependencies": { - "is-number": "^7.0.0" + "@types/unist": "^3.0.0" }, - "engines": { - "node": ">=8.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/toastify-js": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.12.0.tgz", - "integrity": "sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ==", - "license": "MIT" - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tree-dump": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.3.tgz", - "integrity": "sha512-il+Cv80yVHFBwokQSfd4bldvr1Md951DpgAGfmhydt04L+YzHgubm2tQ7zueWDcGENKHq0ZvGFR/hjvNXilHEg==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=10.0" + "dependencies": { + "@types/unist": "^3.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/tributejs": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/tributejs/-/tributejs-5.1.3.tgz", - "integrity": "sha512-B5CXihaVzXw+1UHhNFyAwUTMDk1EfoLP5Tj1VhD9yybZ1I8DZJEv8tZ1l0RJo0t0tk9ZhR8eG5tEsaCvRigmdQ==", - "license": "MIT" - }, - "node_modules/trim-lines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/trough": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", - "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", - "peer": true, "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" + "node": ">= 10.0.0" } }, - "node_modules/ts-loader": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.2.tgz", - "integrity": "sha512-Qo4piXvOTWcMGIgRiuFa6nHNm+54HbYaZCKqc9eeZCLRy3XqafQgwX2F7mofrbJG3g7EEb+lkiR+z2Lic2s3Zw==", + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", - "peer": true, "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4", - "source-map": "^0.7.4" - }, - "engines": { - "node": ">=12.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, - "peerDependencies": { - "typescript": "*", - "webpack": "^5.0.0" - } - }, - "node_modules/ts-loader/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "license": "ISC", - "peer": true, "bin": { - "semver": "bin/semver.js" + "update-browserslist-db": "cli.js" }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "license": "MIT", - "peer": true, + "license": "BSD-2-Clause", "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" + "punycode": "^2.1.0" } }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD", - "peer": true - }, - "node_modules/tty-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/url": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "prelude-ls": "^1.2.1" + "punycode": "^1.4.1", + "qs": "^6.12.3" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 0.4" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "peer": true, + "node_modules/url-join": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "license": "MIT", - "peer": true, "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" } }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true, + "license": "MIT" + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", "license": "MIT", - "peer": true, "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", - "dev": true, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "license": "MIT", - "peer": true, "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, - "engines": { - "node": ">= 0.4" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "node_modules/vite": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", + "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": ">= 0.4" + "node": "^20.19.0 || >=22.12.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", - "devOptional": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "url": "https://github.com/vitejs/vite?sponsor=1" }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-event-target": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/typescript-event-target/-/typescript-event-target-1.1.1.tgz", - "integrity": "sha512-dFSOFBKV6uwaloBCCUhxlD3Pr/P1a/tJdcmPrTXCHlEFD3faj0mztjcGn6VBAhQ0/Bdy8K3VWrrqwbt/ffsYsg==", - "license": "MIT" - }, - "node_modules/ua-is-frozen": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ua-is-frozen/-/ua-is-frozen-0.1.2.tgz", - "integrity": "sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/faisalman" + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true }, - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" + "jiti": { + "optional": true }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - } - ], - "license": "MIT" - }, - "node_modules/ua-parser-js": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-2.0.5.tgz", - "integrity": "sha512-sZErtx3rhpvZQanWW5umau4o/snfoLqRcQwQIZ54377WtRzIecnIKvjpkd5JwPcSUMglGnbIgcsQBGAbdi3S9Q==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" + "less": { + "optional": true }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" + "lightningcss": { + "optional": true }, - { - "type": "github", - "url": "https://github.com/sponsors/faisalman" + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } - ], + } + }, + "node_modules/vite-plugin-css-injected-by-js": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.5.2.tgz", + "integrity": "sha512-2MpU/Y+SCZyWUB6ua3HbJCrgnF0KACAsmzOQt1UvRVJCGF6S8xdA3ZUhWcWdM9ivG4I5az8PnQmwwrkC2CAQrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "vite": ">2.0.0-0" + } + }, + "node_modules/vite-plugin-dts": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-4.5.4.tgz", + "integrity": "sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==", + "dev": true, + "license": "MIT", "dependencies": { - "detect-europe-js": "^0.1.2", - "is-standalone-pwa": "^0.1.1", - "ua-is-frozen": "^0.1.2", - "undici": "^7.12.0" + "@microsoft/api-extractor": "^7.50.1", + "@rollup/pluginutils": "^5.1.4", + "@volar/typescript": "^2.4.11", + "@vue/language-core": "2.2.0", + "compare-versions": "^6.1.1", + "debug": "^4.4.0", + "kolorist": "^1.8.0", + "local-pkg": "^1.0.0", + "magic-string": "^0.30.17" }, - "bin": { - "ua-parser-js": "script/cli.js" + "peerDependencies": { + "typescript": "*", + "vite": "*" }, - "engines": { - "node": "*" + "peerDependenciesMeta": { + "vite": { + "optional": true + } } }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "node_modules/vite-plugin-node-polyfills": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.24.0.tgz", + "integrity": "sha512-GA9QKLH+vIM8NPaGA+o2t8PDfFUl32J8rUp1zQfMKVJQiNkOX4unE51tR6ppl6iKw5yOrDAdSH7r/UIFLCVhLw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" + "@rollup/plugin-inject": "^5.0.5", + "node-stdlib-browser": "^1.2.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/davidmyersdev" + }, + "peerDependencies": { + "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/undici": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.16.0.tgz", - "integrity": "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==", + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=20.18.1" + "node": ">=18" } }, - "node_modules/undici-types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", - "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", - "peer": true + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", - "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=4" + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", - "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=4" - } - }, - "node_modules/unified": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", - "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "bail": "^2.0.0", - "devlop": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node": ">=18" } }, - "node_modules/unist-builder": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-4.0.0.tgz", - "integrity": "sha512-wmRFnH+BLpZnTKpc5L7O67Kac89s9HMrtELpnNaE6TAobq5DTZZs5YaTQfAZBA9bFPECx2uVAPO31c+GVug8mg==", + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/unist-util-find-after": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", - "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/unist-util-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", - "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", - "peer": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.8" + "node": ">=18" } }, - "node_modules/unrs-resolver": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", - "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], "dev": true, - "hasInstallScript": true, "license": "MIT", - "peer": true, - "dependencies": { - "napi-postinstall": "^0.3.0" - }, - "funding": { - "url": "https://opencollective.com/unrs-resolver" - }, - "optionalDependencies": { - "@unrs/resolver-binding-android-arm-eabi": "1.11.1", - "@unrs/resolver-binding-android-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-x64": "1.11.1", - "@unrs/resolver-binding-freebsd-x64": "1.11.1", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", - "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-musl": "1.11.1", - "@unrs/resolver-binding-wasm32-wasi": "1.11.1", - "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", - "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", - "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" ], + "dev": true, "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "punycode": "^2.1.0" + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/url": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", - "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "punycode": "^1.4.1", - "qs": "^6.12.3" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">= 0.4" + "node": ">=18" } }, - "node_modules/url-join": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", - "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" } }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/url/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 0.4.0" + "node": ">=18" } }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "peer": true, - "bin": { - "uuid": "dist/bin/uuid" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 0.8" + "node": ">=18" } }, - "node_modules/vfile": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", - "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "node_modules/vite/node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "vfile-message": "^4.0.0" + "bin": { + "esbuild": "bin/esbuild" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/vfile-message": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" + "engines": { + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/vm-browserify": { @@ -16218,8 +12432,14 @@ "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" }, "node_modules/vue": { "version": "2.7.16", @@ -16250,86 +12470,28 @@ } }, "node_modules/vue-eslint-parser": { - "version": "9.4.3", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", - "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.4.0.tgz", + "integrity": "sha512-Vxi9pJdbN3ZnVGLODVtZ7y4Y2kzAAE2Cm0CZ3ZDRvydVYxZ6VrnBhLikBsRS+dpwj4Jv4UCv21PTEwF5rQ9WXg==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "debug": "^4.3.4", - "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", - "esquery": "^1.4.0", - "lodash": "^4.17.21", - "semver": "^7.3.6" + "debug": "^4.4.0", + "eslint-scope": "^8.2.0 || ^9.0.0", + "eslint-visitor-keys": "^4.2.0 || ^5.0.0", + "espree": "^10.3.0 || ^11.0.0", + "esquery": "^1.6.0", + "semver": "^7.6.3" }, "engines": { - "node": "^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://github.com/sponsors/mysticatea" }, "peerDependencies": { - "eslint": ">=6.0.0" - } - }, - "node_modules/vue-eslint-parser/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/vue-eslint-parser/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/vue-eslint-parser/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0" } }, "node_modules/vue-frag": { @@ -16344,40 +12506,6 @@ "vue": "^2.6.0" } }, - "node_modules/vue-hot-reload-api": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", - "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", - "license": "MIT" - }, - "node_modules/vue-loader": { - "version": "15.11.1", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.11.1.tgz", - "integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==", - "license": "MIT", - "dependencies": { - "@vue/component-compiler-utils": "^3.1.0", - "hash-sum": "^1.0.2", - "loader-utils": "^1.1.0", - "vue-hot-reload-api": "^2.3.0", - "vue-style-loader": "^4.1.0" - }, - "peerDependencies": { - "css-loader": "*", - "webpack": "^3.0.0 || ^4.1.0 || ^5.0.0-0" - }, - "peerDependenciesMeta": { - "cache-loader": { - "optional": true - }, - "prettier": { - "optional": true - }, - "vue-template-compiler": { - "optional": true - } - } - }, "node_modules/vue-material-design-icons": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/vue-material-design-icons/-/vue-material-design-icons-5.3.1.tgz", @@ -16402,22 +12530,6 @@ "integrity": "sha512-VYXZQLtjuvKxxcshuRAwjHnciqZVoXAjTjcqBTz4rKc8qih9g9pI3hbDjmqXaHdgL3v8pV6P8Z335XvHzESxLQ==", "license": "MIT" }, - "node_modules/vue-style-loader": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", - "integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==", - "license": "MIT", - "dependencies": { - "hash-sum": "^1.0.2", - "loader-utils": "^1.0.2" - } - }, - "node_modules/vue-template-es2015-compiler": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", - "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", - "license": "MIT" - }, "node_modules/vue-types": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/vue-types/-/vue-types-5.1.3.tgz", @@ -16473,38 +12585,13 @@ "leaflet": "^1.3.4" } }, - "node_modules/vuex": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz", - "integrity": "sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==", - "license": "MIT", - "peerDependencies": { - "vue": "^2.0.0" - } - }, - "node_modules/watchpack": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", - "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", - "license": "MIT", - "peer": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, + "node_modules/vuex": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz", + "integrity": "sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==", "license": "MIT", - "peer": true, - "dependencies": { - "minimalistic-assert": "^1.0.0" + "peerDependencies": { + "vue": "^2.0.0" } }, "node_modules/web-namespaces": { @@ -16581,314 +12668,12 @@ "url": "https://opencollective.com/node-fetch" } }, - "node_modules/webpack": { - "version": "5.100.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.100.1.tgz", - "integrity": "sha512-YJB/ESPUe2Locd0NKXmw72Dx8fZQk1gTzI6rc9TAT4+Sypbnhl8jd8RywB1bDsDF9Dy1RUR7gn3q/ZJTd0OZZg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.8", - "@types/json-schema": "^7.0.15", - "@webassemblyjs/ast": "^1.14.1", - "@webassemblyjs/wasm-edit": "^1.14.1", - "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.15.0", - "acorn-import-phases": "^1.0.3", - "browserslist": "^4.24.0", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.2", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^4.3.2", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.11", - "watchpack": "^2.4.1", - "webpack-sources": "^3.3.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-cli": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", - "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@discoveryjs/json-ext": "^0.6.1", - "@webpack-cli/configtest": "^3.0.1", - "@webpack-cli/info": "^3.0.1", - "@webpack-cli/serve": "^3.0.1", - "colorette": "^2.0.14", - "commander": "^12.1.0", - "cross-spawn": "^7.0.3", - "envinfo": "^7.14.0", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^3.1.1", - "rechoir": "^0.8.0", - "webpack-merge": "^6.0.1" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.82.0" - }, - "peerDependenciesMeta": { - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/webpack-cli/node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/webpack-dev-middleware": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", - "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^4.6.0", - "mime-types": "^2.1.31", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - } - } - }, - "node_modules/webpack-dev-server": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.2.tgz", - "integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/bonjour": "^3.5.13", - "@types/connect-history-api-fallback": "^1.5.4", - "@types/express": "^4.17.21", - "@types/express-serve-static-core": "^4.17.21", - "@types/serve-index": "^1.9.4", - "@types/serve-static": "^1.15.5", - "@types/sockjs": "^0.3.36", - "@types/ws": "^8.5.10", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.2.1", - "chokidar": "^3.6.0", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^2.0.0", - "express": "^4.21.2", - "graceful-fs": "^4.2.6", - "http-proxy-middleware": "^2.0.9", - "ipaddr.js": "^2.1.0", - "launch-editor": "^2.6.1", - "open": "^10.0.3", - "p-retry": "^6.2.0", - "schema-utils": "^4.2.0", - "selfsigned": "^2.4.1", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^7.4.2", - "ws": "^8.18.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-server/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/webpack-dev-server/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/webpack-dev-server/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/webpack-merge": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", - "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", - "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "isexe": "^2.0.0" }, @@ -16899,83 +12684,12 @@ "node": ">= 8" } }, - "node_modules/which-boxed-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", - "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", - "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/which-typed-array": { "version": "1.1.19", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", @@ -16992,33 +12706,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC", - "peer": true - }, "node_modules/write-file-atomic": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", @@ -17034,53 +12731,12 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/wsl-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", - "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-wsl": "^3.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "dev": true, "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=12" } @@ -17091,25 +12747,16 @@ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.4" } }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 6557b899e..bf32256b0 100644 --- a/package.json +++ b/package.json @@ -6,14 +6,15 @@ "directories": { "test": "tests" }, + "type": "module", "scripts": { - "dev": "NODE_ENV=development npx webpack --progress --config webpack.js", - "watch": "NODE_ENV=development npx webpack --progress --watch --config webpack.js", - "build": "NODE_ENV=production npx webpack --progress --config webpack.js", - "lint": "eslint --ext .js,.vue src", - "lint:fix": "eslint --ext .js,.vue src --fix", - "stylelint": "stylelint **/*.css **/*.scss **/*.vue", - "stylelint:fix": "stylelint **/*.css **/*.scss **/*.vue --fix" + "build": "vite --mode production build", + "dev": "export NODE_ENV=development; vite --mode development build", + "watch": "export NODE_ENV=development; vite --mode development build --watch", + "lint": "eslint src", + "lint:fix": "eslint src --fix", + "stylelint": "stylelint src", + "stylelint:fix": "stylelint src --fix" }, "repository": { "type": "git", @@ -73,7 +74,7 @@ "ua-parser-js": "^2.0.5", "vue": "^2.7.16", "vue-click-outside": "^1.1.0", - "vue-loader": "^15.11.1", + "vue-material-design-icons": "^5.3.1", "vue-types": "^5.1.3", "vue2-leaflet": "^2.6.0", @@ -81,14 +82,15 @@ "vuex": "^3.6.2" }, "devDependencies": { - "@babel/plugin-proposal-object-rest-spread": "^7.20.7", - "@nextcloud/babel-config": "^1.3.0", "@nextcloud/browserslist-config": "^3.0.1", - "@nextcloud/eslint-config": "^8.4.1", + "@nextcloud/eslint-config": "^9.0.0-rc.9", "@nextcloud/stylelint-config": "^3.1.0", - "@nextcloud/webpack-vue-config": "^6.3.0", + "@nextcloud/vite-config": "^1.7.2", "@types/leaflet": "^1.9.21", "@vue/tsconfig": "^0.5.1", - "typescript": "^5.9.2" + "eslint": "^10.2.1", + "sass": "^1.99.0", + "typescript": "^5.9.2", + "vite": "^7.3.2" } } diff --git a/src/bootstrap.js b/src/bootstrap.js index 9b0490e9d..a4b229ca3 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -22,6 +22,9 @@ import Vue from 'vue' import { Icon } from 'leaflet' +import markerIcon2x from 'leaflet/dist/images/marker-icon-2x.png' +import markerIcon from 'leaflet/dist/images/marker-icon.png' +import markerShadow from 'leaflet/dist/images/marker-shadow.png' Vue.prototype.t = window.t Vue.prototype.n = window.n @@ -36,7 +39,7 @@ Vue.prototype.OCA = window.OCA delete Icon.Default.prototype._getIconUrl Icon.Default.mergeOptions({ - iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png').default, - iconUrl: require('leaflet/dist/images/marker-icon.png').default, - shadowUrl: require('leaflet/dist/images/marker-shadow.png').default, + iconRetinaUrl: markerIcon2x, + iconUrl: markerIcon, + shadowUrl: markerShadow, }) diff --git a/src/components/Map.vue b/src/components/Map.vue index e5f4eb13e..2590d6a41 100644 --- a/src/components/Map.vue +++ b/src/components/Map.vue @@ -1117,9 +1117,9 @@ export default { diff --git a/src/components/MapContainer.vue b/src/components/MapContainer.vue index 58b112f5c..77beadf8d 100644 --- a/src/components/MapContainer.vue +++ b/src/components/MapContainer.vue @@ -21,46 +21,38 @@ diff --git a/src/components/map/ClickSearchPopup.vue b/src/components/map/ClickSearchPopup.vue index b2a602719..3dae5ae73 100644 --- a/src/components/map/ClickSearchPopup.vue +++ b/src/components/map/ClickSearchPopup.vue @@ -1,39 +1,38 @@