diff --git a/package.json b/package.json index 3e92ca65b..c804db203 100644 --- a/package.json +++ b/package.json @@ -199,7 +199,7 @@ "detect-port": "^1.3.0", "dotenv": "^10.0.0", "dotenv-webpack": "^7.0.3", - "electron": "^25.8.4", + "electron": "^19.1.9", "electron-builder": "^23.6.0", "electron-devtools-installer": "^3.2.0", "electron-notarize": "^1.1.1", diff --git a/release/app/yarn.lock b/release/app/yarn.lock index ebb2bf8c9..abc41fb32 100644 --- a/release/app/yarn.lock +++ b/release/app/yarn.lock @@ -30,6 +30,14 @@ enabled "2.0.x" kuler "^2.0.0" +"@gcas/fuse@^2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@gcas/fuse/-/fuse-2.4.2.tgz#149bd97ec8a60988f4868bacd719c7e8a1c41876" + integrity sha512-l/vVd2eXAuzKG4QilN1VRa8za5glndSK+jxcLrzMiXRrvbbCJthwqcBZUE3VzoRL0T/l7197tW+MKR9YeQCtZQ== + dependencies: + nanoresource "^1.3.0" + napi-macros "^2.0.0" + "@ioredis/commands@^1.1.1": version "1.2.0" resolved "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz" @@ -664,11 +672,23 @@ mz@^2.4.0: object-assign "^4.0.1" thenify-all "^1.0.0" +nanoresource@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/nanoresource/-/nanoresource-1.3.0.tgz#823945d9667ab3e81a8b2591ab8d734552878cd0" + integrity sha512-OI5dswqipmlYfyL3k/YMm7mbERlh4Bd1KuKdMHpeoVD1iVxqxaTMKleB4qaA2mbQZ6/zMNSxCXv9M9P/YbqTuQ== + dependencies: + inherits "^2.0.4" + napi-build-utils@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== +napi-macros@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.2.2.tgz#817fef20c3e0e40a963fbf7b37d1600bd0201044" + integrity sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g== + node-abi@^3.3.0: version "3.51.0" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.51.0.tgz#970bf595ef5a26a271307f8a4befa02823d4e87d" diff --git a/src/apps/fuse/callbacks/GetAttributesCallback.ts b/src/apps/fuse/callbacks/GetAttributesCallback.ts index a254f5c2d..6d4f6bf1e 100644 --- a/src/apps/fuse/callbacks/GetAttributesCallback.ts +++ b/src/apps/fuse/callbacks/GetAttributesCallback.ts @@ -60,9 +60,10 @@ export class GetAttributesCallback extends FuseCallback> { } async execute(path: string) { + const folderPath = new FolderPath(path); + const filesNamesPromise = - this.container.filesByFolderPathNameLister.run(path); + this.container.filesByFolderPathNameLister.run(folderPath); const folderNamesPromise = - this.container.foldersByParentPathLister.run(path); + this.container.foldersByParentPathLister.run(folderPath); const [filesNames, foldersNames] = await Promise.all([ filesNamesPromise, diff --git a/src/apps/fuse/callbacks/RenameOrMoveFolder.ts b/src/apps/fuse/callbacks/RenameOrMoveFolder.ts index f0891d077..bd36f8217 100644 --- a/src/apps/fuse/callbacks/RenameOrMoveFolder.ts +++ b/src/apps/fuse/callbacks/RenameOrMoveFolder.ts @@ -3,6 +3,7 @@ import { FolderPath } from '../../../context/virtual-drive/folders/domain/Folder import { VirtualDriveDependencyContainer } from '../dependency-injection/virtual-drive/VirtualDriveDependencyContainer'; import { FuseError, FuseUnknownError } from './FuseErrors'; import { Either, left, right } from '../../../context/shared/domain/Either'; +import { FolderStatuses } from '../../../context/virtual-drive/folders/domain/FolderStatus'; type RenameOrMoveRight = 'no-op' | 'success'; @@ -16,7 +17,10 @@ export class RenameOrMoveFolder { src: string, dest: string ): Promise> { - const folder = await this.container.folderSearcher.run({ path: src }); + const folder = await this.container.singleFolderMatchingSearcher.run({ + path: src, + status: FolderStatuses.EXISTS, + }); if (!folder) { return right(RenameOrMoveFolder.NO_OP); diff --git a/src/apps/fuse/callbacks/TrashFolderCallback.ts b/src/apps/fuse/callbacks/TrashFolderCallback.ts index 007b5d39e..caaca0b35 100644 --- a/src/apps/fuse/callbacks/TrashFolderCallback.ts +++ b/src/apps/fuse/callbacks/TrashFolderCallback.ts @@ -1,6 +1,6 @@ +import { FolderStatuses } from '../../../context/virtual-drive/folders/domain/FolderStatus'; import { VirtualDriveDependencyContainer } from '../dependency-injection/virtual-drive/VirtualDriveDependencyContainer'; import { NotifyFuseCallback } from './FuseCallback'; -import { FuseNoSuchFileOrDirectoryError } from './FuseErrors'; import { basename } from 'path'; export class TrashFolderCallback extends NotifyFuseCallback { @@ -9,13 +9,12 @@ export class TrashFolderCallback extends NotifyFuseCallback { } async execute(path: string) { - const folder = await this.container.folderSearcher.run({ path }); - - if (!folder) { - return this.left(new FuseNoSuchFileOrDirectoryError()); - } - try { + const folder = await this.container.singleFolderMatchingFinder.run({ + path, + status: FolderStatuses.EXISTS, + }); + await this.container.folderDeleter.run(folder.uuid); return this.right(); diff --git a/src/apps/fuse/dependency-injection/virtual-drive/files/FilesContainer.ts b/src/apps/fuse/dependency-injection/virtual-drive/files/FilesContainer.ts index 78d6c8072..95126b76a 100644 --- a/src/apps/fuse/dependency-injection/virtual-drive/files/FilesContainer.ts +++ b/src/apps/fuse/dependency-injection/virtual-drive/files/FilesContainer.ts @@ -1,4 +1,4 @@ -import { FilesSearcher } from '../../../../../context/virtual-drive/files/application/FilesSearcher'; +import { FirstsFileSearcher } from '../../../../../context/virtual-drive/files/application/FirstsFileSearcher'; import { FilesByFolderPathSearcher } from '../../../../../context/virtual-drive/files/application/FilesByFolderPathSearcher'; import { FilePathUpdater } from '../../../../../context/virtual-drive/files/application/FilePathUpdater'; import { FileCreator } from '../../../../../context/virtual-drive/files/application/FileCreator'; @@ -10,7 +10,7 @@ import { SyncFileMessenger } from '../../../../../context/virtual-drive/files/do export interface FilesContainer { filesByFolderPathNameLister: FilesByFolderPathSearcher; - filesSearcher: FilesSearcher; + filesSearcher: FirstsFileSearcher; filePathUpdater: FilePathUpdater; fileCreator: FileCreator; fileDeleter: FileDeleter; diff --git a/src/apps/fuse/dependency-injection/virtual-drive/files/builder.ts b/src/apps/fuse/dependency-injection/virtual-drive/files/builder.ts index bb4e9f9ad..cacdc3daf 100644 --- a/src/apps/fuse/dependency-injection/virtual-drive/files/builder.ts +++ b/src/apps/fuse/dependency-injection/virtual-drive/files/builder.ts @@ -4,7 +4,7 @@ import { FileCreator } from '../../../../../context/virtual-drive/files/applicat import { FileDeleter } from '../../../../../context/virtual-drive/files/application/FileDeleter'; import { FilePathUpdater } from '../../../../../context/virtual-drive/files/application/FilePathUpdater'; import { FilesByFolderPathSearcher } from '../../../../../context/virtual-drive/files/application/FilesByFolderPathSearcher'; -import { FilesSearcher } from '../../../../../context/virtual-drive/files/application/FilesSearcher'; +import { FirstsFileSearcher } from '../../../../../context/virtual-drive/files/application/FirstsFileSearcher'; import { FileRepositoryInitializer } from '../../../../../context/virtual-drive/files/application/FileRepositoryInitializer'; import { SameFileWasMoved } from '../../../../../context/virtual-drive/files/application/SameFileWasMoved'; import { File } from '../../../../../context/virtual-drive/files/domain/File'; @@ -20,6 +20,7 @@ import { FoldersContainer } from '../folders/FoldersContainer'; import { SharedContainer } from '../shared/SharedContainer'; import { FilesContainer } from './FilesContainer'; import { InMemoryFileRepositorySingleton } from '../../../../shared/dependency-injection/virtual-drive/files/InMemoryFileRepositorySingleton'; +import { SingleFileMatchingSearcher } from '../../../../../context/virtual-drive/files/application/SingleFileMatchingSearcher'; export async function buildFilesContainer( initialFiles: Array, @@ -41,10 +42,10 @@ export async function buildFilesContainer( const filesByFolderPathNameLister = new FilesByFolderPathSearcher( repository, - folderContainer.folderFinder + folderContainer.parentFolderFinder ); - const filesSearcher = new FilesSearcher(repository); + const filesSearcher = new FirstsFileSearcher(repository); const remoteFileSystem = new SDKRemoteFileSystem( sdk, @@ -56,16 +57,19 @@ export async function buildFilesContainer( sharedContainer.relativePathToAbsoluteConverter ); + const singleFileMatchingSearcher = new SingleFileMatchingSearcher(repository); + const filePathUpdater = new FilePathUpdater( remoteFileSystem, localFileSystem, repository, - folderContainer.folderFinder, + singleFileMatchingSearcher, + folderContainer.parentFolderFinder, eventBus ); const sameFileWasMoved = new SameFileWasMoved( - repository, + singleFileMatchingSearcher, localFileSystem, eventRepository ); @@ -81,7 +85,7 @@ export async function buildFilesContainer( const fileCreator = new FileCreator( remoteFileSystem, repository, - folderContainer.folderFinder, + folderContainer.parentFolderFinder, fileDeleter, eventBus, syncFileMessenger diff --git a/src/apps/fuse/dependency-injection/virtual-drive/folders/FoldersContainer.ts b/src/apps/fuse/dependency-injection/virtual-drive/folders/FoldersContainer.ts index 96f552530..9a2f848a9 100644 --- a/src/apps/fuse/dependency-injection/virtual-drive/folders/FoldersContainer.ts +++ b/src/apps/fuse/dependency-injection/virtual-drive/folders/FoldersContainer.ts @@ -2,16 +2,16 @@ import { AllParentFoldersStatusIsExists } from '../../../../../context/virtual-d import { FolderCreator } from '../../../../../context/virtual-drive/folders/application/FolderCreator'; import { FolderCreatorFromOfflineFolder } from '../../../../../context/virtual-drive/folders/application/FolderCreatorFromOfflineFolder'; import { FolderDeleter } from '../../../../../context/virtual-drive/folders/application/FolderDeleter'; -import { FolderFinder } from '../../../../../context/virtual-drive/folders/application/FolderFinder'; import { FolderPathUpdater } from '../../../../../context/virtual-drive/folders/application/FolderPathUpdater'; import { FolderRepositoryInitializer } from '../../../../../context/virtual-drive/folders/application/FolderRepositoryInitializer'; -import { FolderSearcher } from '../../../../../context/virtual-drive/folders/application/FolderSearcher'; import { FoldersByParentPathLister } from '../../../../../context/virtual-drive/folders/application/FoldersByParentPathLister'; +import { ParentFolderFinder } from '../../../../../context/virtual-drive/folders/application/ParentFolderFinder'; +import { SingleFolderMatchingFinder } from '../../../../../context/virtual-drive/folders/application/SingleFolderMatchingFinder'; +import { SingleFolderMatchingSearcher } from '../../../../../context/virtual-drive/folders/application/SingleFolderMatchingSearcher'; import { SyncFolderMessenger } from '../../../../../context/virtual-drive/folders/domain/SyncFolderMessenger'; export interface FoldersContainer { - folderFinder: FolderFinder; - folderSearcher: FolderSearcher; + parentFolderFinder: ParentFolderFinder; foldersByParentPathLister: FoldersByParentPathLister; folderPathUpdater: FolderPathUpdater; allParentFoldersStatusIsExists: AllParentFoldersStatusIsExists; @@ -20,4 +20,6 @@ export interface FoldersContainer { folderDeleter: FolderDeleter; folderRepositoryInitiator: FolderRepositoryInitializer; syncFolderMessenger: SyncFolderMessenger; + singleFolderMatchingFinder: SingleFolderMatchingFinder; + singleFolderMatchingSearcher: SingleFolderMatchingSearcher; } diff --git a/src/apps/fuse/dependency-injection/virtual-drive/folders/builder.ts b/src/apps/fuse/dependency-injection/virtual-drive/folders/builder.ts index 7cf00a97f..4488d9625 100644 --- a/src/apps/fuse/dependency-injection/virtual-drive/folders/builder.ts +++ b/src/apps/fuse/dependency-injection/virtual-drive/folders/builder.ts @@ -2,12 +2,11 @@ import { AllParentFoldersStatusIsExists } from '../../../../../context/virtual-d import { FolderCreator } from '../../../../../context/virtual-drive/folders/application/FolderCreator'; import { FolderCreatorFromOfflineFolder } from '../../../../../context/virtual-drive/folders/application/FolderCreatorFromOfflineFolder'; import { FolderDeleter } from '../../../../../context/virtual-drive/folders/application/FolderDeleter'; -import { FolderFinder } from '../../../../../context/virtual-drive/folders/application/FolderFinder'; +import { ParentFolderFinder } from '../../../../../context/virtual-drive/folders/application/ParentFolderFinder'; import { FolderMover } from '../../../../../context/virtual-drive/folders/application/FolderMover'; import { FolderPathUpdater } from '../../../../../context/virtual-drive/folders/application/FolderPathUpdater'; import { FolderRenamer } from '../../../../../context/virtual-drive/folders/application/FolderRenamer'; import { FolderRepositoryInitializer } from '../../../../../context/virtual-drive/folders/application/FolderRepositoryInitializer'; -import { FolderSearcher } from '../../../../../context/virtual-drive/folders/application/FolderSearcher'; import { FoldersByParentPathLister } from '../../../../../context/virtual-drive/folders/application/FoldersByParentPathLister'; import { Folder } from '../../../../../context/virtual-drive/folders/domain/Folder'; import { FuseLocalFileSystem } from '../../../../../context/virtual-drive/folders/infrastructure/FuseLocalFileSystem'; @@ -18,6 +17,8 @@ import { DependencyInjectionHttpClientsProvider } from '../../common/clients'; import { DependencyInjectionEventBus } from '../../common/eventBus'; import { FoldersContainer } from './FoldersContainer'; +import { SingleFolderMatchingFinder } from '../../../../../context/virtual-drive/folders/application/SingleFolderMatchingFinder'; +import { SingleFolderMatchingSearcher } from '../../../../../context/virtual-drive/folders/application/SingleFolderMatchingSearcher'; export async function buildFoldersContainer( initialFolders: Array @@ -41,19 +42,21 @@ export async function buildFoldersContainer( await folderRepositoryInitiator.run(initialFolders); - const folderFinder = new FolderFinder(repository); - - const folderSearcher = new FolderSearcher(repository); + const parentFolderFinder = new ParentFolderFinder(repository); + const singleFolderMatchingFinder = new SingleFolderMatchingFinder(repository); + const singleFolderMatchingSearcher = new SingleFolderMatchingSearcher( + repository + ); const foldersByParentPathSearcher = new FoldersByParentPathLister( - folderFinder, + parentFolderFinder, repository ); const folderMover = new FolderMover( repository, remoteFileSystem, - folderFinder + parentFolderFinder ); const folderRenamer = new FolderRenamer( @@ -82,6 +85,7 @@ export async function buildFoldersContainer( const folderCreator = new FolderCreator( repository, + parentFolderFinder, remoteFileSystem, eventBus ); @@ -94,8 +98,7 @@ export async function buildFoldersContainer( ); return { - folderFinder, - folderSearcher, + parentFolderFinder, foldersByParentPathLister: foldersByParentPathSearcher, folderPathUpdater, allParentFoldersStatusIsExists, @@ -104,5 +107,7 @@ export async function buildFoldersContainer( folderDeleter, syncFolderMessenger, folderRepositoryInitiator, + singleFolderMatchingFinder, + singleFolderMatchingSearcher, }; } diff --git a/src/apps/hydration-api/controllers/files.ts b/src/apps/hydration-api/controllers/files.ts index 163ec095d..026ec6b4f 100644 --- a/src/apps/hydration-api/controllers/files.ts +++ b/src/apps/hydration-api/controllers/files.ts @@ -6,10 +6,12 @@ export function buildFilesControllers(container: DependencyContainer) { const getAll = async (_req: Request, res: Response) => { const files = await container.retrieveAllFiles.run(); - res.status(200).send({ files }); + const result = files.map((file) => file.attributes()); + + res.status(200).send({ files: result }); }; - const getByPartial = async (req: Request, res: Response) => { + const filter = async (req: Request, res: Response) => { const filter = Object.entries(req.query) .map(([key, param]) => { @@ -29,8 +31,8 @@ export function buildFilesControllers(container: DependencyContainer) { return; } - res.status(200).send({ file }); + res.status(200).send({ file: file.attributes() }); }; - return { getAll, getByPartial }; + return { getAll, getByPartial: filter }; } diff --git a/src/apps/hydration-api/dependency-injection/files/FilesContainer.ts b/src/apps/hydration-api/dependency-injection/files/FilesContainer.ts index 062fed065..69536da8d 100644 --- a/src/apps/hydration-api/dependency-injection/files/FilesContainer.ts +++ b/src/apps/hydration-api/dependency-injection/files/FilesContainer.ts @@ -1,9 +1,9 @@ -import { FilesSearcher } from '../../../../context/virtual-drive/files/application/FilesSearcher'; +import { FirstsFileSearcher } from '../../../../context/virtual-drive/files/application/FirstsFileSearcher'; import { FilesByFolderPathSearcher } from '../../../../context/virtual-drive/files/application/FilesByFolderPathSearcher'; import { RetrieveAllFiles } from '../../../../context/virtual-drive/files/application/RetrieveAllFiles'; export interface FilesContainer { filesByFolderPathNameLister: FilesByFolderPathSearcher; - filesSearcher: FilesSearcher; + filesSearcher: FirstsFileSearcher; retrieveAllFiles: RetrieveAllFiles; } diff --git a/src/apps/hydration-api/dependency-injection/files/builder.ts b/src/apps/hydration-api/dependency-injection/files/builder.ts index 5277af7e0..3ee93c161 100644 --- a/src/apps/hydration-api/dependency-injection/files/builder.ts +++ b/src/apps/hydration-api/dependency-injection/files/builder.ts @@ -1,5 +1,5 @@ import { FilesByFolderPathSearcher } from '../../../../context/virtual-drive/files/application/FilesByFolderPathSearcher'; -import { FilesSearcher } from '../../../../context/virtual-drive/files/application/FilesSearcher'; +import { FirstsFileSearcher } from '../../../../context/virtual-drive/files/application/FirstsFileSearcher'; import { RetrieveAllFiles } from '../../../../context/virtual-drive/files/application/RetrieveAllFiles'; import { InMemoryFileRepositorySingleton } from '../../../shared/dependency-injection/virtual-drive/files/InMemoryFileRepositorySingleton'; import { FoldersContainer } from '../folders/FoldersContainer'; @@ -12,10 +12,10 @@ export async function buildFilesContainer( const filesByFolderPathNameLister = new FilesByFolderPathSearcher( repository, - folderContainer.folderFinder + folderContainer.parentFolderFinder ); - const filesSearcher = new FilesSearcher(repository); + const filesSearcher = new FirstsFileSearcher(repository); const retrieveAllFiles = new RetrieveAllFiles(repository); diff --git a/src/apps/hydration-api/dependency-injection/folders/FoldersContainer.ts b/src/apps/hydration-api/dependency-injection/folders/FoldersContainer.ts index 6dd4b46a7..e08ff0b4a 100644 --- a/src/apps/hydration-api/dependency-injection/folders/FoldersContainer.ts +++ b/src/apps/hydration-api/dependency-injection/folders/FoldersContainer.ts @@ -1,9 +1,7 @@ -import { FolderFinder } from '../../../../context/virtual-drive/folders/application/FolderFinder'; -import { FolderSearcher } from '../../../../context/virtual-drive/folders/application/FolderSearcher'; +import { ParentFolderFinder } from '../../../../context/virtual-drive/folders/application/ParentFolderFinder'; import { FoldersByParentPathLister } from '../../../../context/virtual-drive/folders/application/FoldersByParentPathLister'; export interface FoldersContainer { - folderFinder: FolderFinder; - folderSearcher: FolderSearcher; + parentFolderFinder: ParentFolderFinder; foldersByParentPathSearcher: FoldersByParentPathLister; } diff --git a/src/apps/hydration-api/dependency-injection/folders/builder.ts b/src/apps/hydration-api/dependency-injection/folders/builder.ts index d52c66964..c9247748d 100644 --- a/src/apps/hydration-api/dependency-injection/folders/builder.ts +++ b/src/apps/hydration-api/dependency-injection/folders/builder.ts @@ -1,5 +1,4 @@ -import { FolderFinder } from '../../../../context/virtual-drive/folders/application/FolderFinder'; -import { FolderSearcher } from '../../../../context/virtual-drive/folders/application/FolderSearcher'; +import { ParentFolderFinder } from '../../../../context/virtual-drive/folders/application/ParentFolderFinder'; import { FoldersByParentPathLister } from '../../../../context/virtual-drive/folders/application/FoldersByParentPathLister'; import { InMemoryFolderRepository } from '../../../../context/virtual-drive/folders/infrastructure/InMemoryFolderRepository'; import { FoldersContainer } from './FoldersContainer'; @@ -7,18 +6,15 @@ import { FoldersContainer } from './FoldersContainer'; export async function buildFoldersContainer(): Promise { const repository = new InMemoryFolderRepository(); - const folderFinder = new FolderFinder(repository); - - const folderSearcher = new FolderSearcher(repository); + const parentFolderFinder = new ParentFolderFinder(repository); const foldersByParentPathSearcher = new FoldersByParentPathLister( - folderFinder, + parentFolderFinder, repository ); return { - folderFinder, - folderSearcher, + parentFolderFinder, foldersByParentPathSearcher, }; } diff --git a/src/apps/sync-engine/BindingManager.ts b/src/apps/sync-engine/BindingManager.ts index 8a00b08ce..8a53f5e7c 100644 --- a/src/apps/sync-engine/BindingManager.ts +++ b/src/apps/sync-engine/BindingManager.ts @@ -91,7 +91,7 @@ export class BindingsManager { callback ); Logger.debug('Execute Fetch Data Callback, sending path:', path); - const file = controllers.downloadFile.fileFinderByContentsId( + const file = await controllers.downloadFile.fileFinderByContentsId( contentsId .replace( // eslint-disable-next-line no-control-regex diff --git a/src/apps/sync-engine/callbacks-controllers/buildControllers.ts b/src/apps/sync-engine/callbacks-controllers/buildControllers.ts index c492d32c5..0612327b1 100644 --- a/src/apps/sync-engine/callbacks-controllers/buildControllers.ts +++ b/src/apps/sync-engine/callbacks-controllers/buildControllers.ts @@ -27,7 +27,7 @@ export function buildControllers(container: SyncEngineDependencyContainer) { ); const downloadFileController = new DownloadFileController( - container.fileFinderByContentsId, + container.singleFileMatchingFinder, container.contentsDownloader ); diff --git a/src/apps/sync-engine/callbacks-controllers/controllers/AddController.ts b/src/apps/sync-engine/callbacks-controllers/controllers/AddController.ts index f16a5930d..ac81949c1 100644 --- a/src/apps/sync-engine/callbacks-controllers/controllers/AddController.ts +++ b/src/apps/sync-engine/callbacks-controllers/controllers/AddController.ts @@ -80,7 +80,9 @@ export class AddController extends CallbackController { } }; private async runFolderCreator(posixRelativePath: string): Promise { - const offlineFolder = this.offlineFolderCreator.run(posixRelativePath); + const offlineFolder = await this.offlineFolderCreator.run( + posixRelativePath + ); return this.folderCreator.run(offlineFolder); } @@ -111,7 +113,7 @@ export class AddController extends CallbackController { posixRelativePath: string ): Promise { try { - return this.offlineFolderCreator.run(posixRelativePath); + return await this.offlineFolderCreator.run(posixRelativePath); } catch (error) { if (error instanceof FolderNotFoundError) { // father created diff --git a/src/apps/sync-engine/callbacks-controllers/controllers/DownloadFileController.ts b/src/apps/sync-engine/callbacks-controllers/controllers/DownloadFileController.ts index 6e5b8bfbc..67f9f12c8 100644 --- a/src/apps/sync-engine/callbacks-controllers/controllers/DownloadFileController.ts +++ b/src/apps/sync-engine/callbacks-controllers/controllers/DownloadFileController.ts @@ -1,26 +1,26 @@ import Logger from 'electron-log'; import { ContentsDownloader } from '../../../../context/virtual-drive/contents/application/ContentsDownloader'; -import { FileFinderByContentsId } from '../../../../context/virtual-drive/files/application/FileFinderByContentsId'; import { FilePlaceholderId } from '../../../../context/virtual-drive/files/domain/PlaceholderId'; import { CallbackDownload } from '../../BindingManager'; import { CallbackController } from './CallbackController'; +import { SingleFileMatchingFinder } from '../../../../context/virtual-drive/files/application/SingleFileMatchingFinder'; export class DownloadFileController extends CallbackController { constructor( - private readonly fileFinder: FileFinderByContentsId, + private readonly fileFinder: SingleFileMatchingFinder, private readonly downloader: ContentsDownloader ) { super(); } private async action(id: string, cb: CallbackDownload): Promise { - const file = this.fileFinder.run(id); + const file = await this.fileFinder.run({ contentsId: id }); return await this.downloader.run(file, cb); } fileFinderByContentsId(contentsId: string) { - return this.fileFinder.run(contentsId); + return this.fileFinder.run({ contentsId }); } async execute( diff --git a/src/apps/sync-engine/dependency-injection/files/FilesContainer.ts b/src/apps/sync-engine/dependency-injection/files/FilesContainer.ts index bf9fcf40a..48a99c5c7 100644 --- a/src/apps/sync-engine/dependency-injection/files/FilesContainer.ts +++ b/src/apps/sync-engine/dependency-injection/files/FilesContainer.ts @@ -1,7 +1,6 @@ import { CreateFilePlaceholderOnDeletionFailed } from '../../../../context/virtual-drive/files/application/CreateFilePlaceholderOnDeletionFailed'; import { FileCreator } from '../../../../context/virtual-drive/files/application/FileCreator'; import { FileDeleter } from '../../../../context/virtual-drive/files/application/FileDeleter'; -import { FileFinderByContentsId } from '../../../../context/virtual-drive/files/application/FileFinderByContentsId'; import { FilePathUpdater } from '../../../../context/virtual-drive/files/application/FilePathUpdater'; import { FilePlaceholderCreatorFromContentsId } from '../../../../context/virtual-drive/files/application/FilePlaceholderCreatorFromContentsId'; import { FilesPlaceholderUpdater } from '../../../../context/virtual-drive/files/application/FilesPlaceholderUpdater'; @@ -9,9 +8,9 @@ import { FilesPlaceholderCreator } from '../../../../context/virtual-drive/files import { FileRepositoryInitializer } from '../../../../context/virtual-drive/files/application/FileRepositoryInitializer'; import { RetrieveAllFiles } from '../../../../context/virtual-drive/files/application/RetrieveAllFiles'; import { SameFileWasMoved } from '../../../../context/virtual-drive/files/application/SameFileWasMoved'; +import { SingleFileMatchingFinder } from '../../../../context/virtual-drive/files/application/SingleFileMatchingFinder'; export interface FilesContainer { - fileFinderByContentsId: FileFinderByContentsId; fileDeleter: FileDeleter; filePathUpdater: FilePathUpdater; fileCreator: FileCreator; @@ -22,4 +21,5 @@ export interface FilesContainer { repositoryPopulator: FileRepositoryInitializer; filesPlaceholderCreator: FilesPlaceholderCreator; filesPlaceholderUpdater: FilesPlaceholderUpdater; + singleFileMatchingFinder: SingleFileMatchingFinder; } diff --git a/src/apps/sync-engine/dependency-injection/files/builder.ts b/src/apps/sync-engine/dependency-injection/files/builder.ts index ca9acc619..885f45c3a 100644 --- a/src/apps/sync-engine/dependency-injection/files/builder.ts +++ b/src/apps/sync-engine/dependency-injection/files/builder.ts @@ -2,7 +2,6 @@ import crypt from '../../../../context/shared/infrastructure/crypt'; import { CreateFilePlaceholderOnDeletionFailed } from '../../../../context/virtual-drive/files/application/CreateFilePlaceholderOnDeletionFailed'; import { FileCreator } from '../../../../context/virtual-drive/files/application/FileCreator'; import { FileDeleter } from '../../../../context/virtual-drive/files/application/FileDeleter'; -import { FileFinderByContentsId } from '../../../../context/virtual-drive/files/application/FileFinderByContentsId'; import { FilePathUpdater } from '../../../../context/virtual-drive/files/application/FilePathUpdater'; import { FilePlaceholderCreatorFromContentsId } from '../../../../context/virtual-drive/files/application/FilePlaceholderCreatorFromContentsId'; import { FilesPlaceholderUpdater } from '../../../../context/virtual-drive/files/application/FilesPlaceholderUpdater'; @@ -25,6 +24,8 @@ import { DependencyInjectionVirtualDrive } from '../common/virtualDrive'; import { FoldersContainer } from '../folders/FoldersContainer'; import { SharedContainer } from '../shared/SharedContainer'; import { FilesContainer } from './FilesContainer'; +import { SingleFileMatchingSearcher } from '../../../../context/virtual-drive/files/application/SingleFileMatchingSearcher'; +import { SingleFileMatchingFinder } from '../../../../context/virtual-drive/files/application/SingleFileMatchingFinder'; export async function buildFilesContainer( folderContainer: FoldersContainer, @@ -58,7 +59,8 @@ export async function buildFilesContainer( const repository = new InMemoryFileRepository(); - const fileFinderByContentsId = new FileFinderByContentsId(repository); + const singleFileMatchingSearcher = new SingleFileMatchingSearcher(repository); + const singleFileMatchingFinder = new SingleFileMatchingFinder(repository); const fileDeleter = new FileDeleter( remoteFileSystem, @@ -69,7 +71,7 @@ export async function buildFilesContainer( ); const sameFileWasMoved = new SameFileWasMoved( - repository, + singleFileMatchingSearcher, localFileSystem, eventHistory ); @@ -78,14 +80,15 @@ export async function buildFilesContainer( remoteFileSystem, localFileSystem, repository, - folderContainer.folderFinder, + singleFileMatchingSearcher, + folderContainer.parentFolderFinder, eventBus ); const fileCreator = new FileCreator( remoteFileSystem, repository, - folderContainer.folderFinder, + folderContainer.parentFolderFinder, fileDeleter, eventBus, syncFileMessenger @@ -93,7 +96,7 @@ export async function buildFilesContainer( const filePlaceholderCreatorFromContentsId = new FilePlaceholderCreatorFromContentsId( - fileFinderByContentsId, + singleFileMatchingFinder, localFileSystem ); @@ -119,7 +122,6 @@ export async function buildFilesContainer( ); const container: FilesContainer = { - fileFinderByContentsId, fileDeleter, filePathUpdater, fileCreator, @@ -131,6 +133,7 @@ export async function buildFilesContainer( repositoryPopulator: repositoryPopulator, filesPlaceholderCreator, filesPlaceholderUpdater, + singleFileMatchingFinder, }; return { container, subscribers: [] }; diff --git a/src/apps/sync-engine/dependency-injection/folders/FoldersContainer.ts b/src/apps/sync-engine/dependency-injection/folders/FoldersContainer.ts index 623806105..127348b21 100644 --- a/src/apps/sync-engine/dependency-injection/folders/FoldersContainer.ts +++ b/src/apps/sync-engine/dependency-injection/folders/FoldersContainer.ts @@ -1,8 +1,7 @@ import { AllParentFoldersStatusIsExists } from '../../../../context/virtual-drive/folders/application/AllParentFoldersStatusIsExists'; -import { FolderByPartialSearcher } from '../../../../context/virtual-drive/folders/application/FolderByPartialSearcher'; import { FolderCreatorFromOfflineFolder } from '../../../../context/virtual-drive/folders/application/FolderCreatorFromOfflineFolder'; import { FolderDeleter } from '../../../../context/virtual-drive/folders/application/FolderDeleter'; -import { FolderFinder } from '../../../../context/virtual-drive/folders/application/FolderFinder'; +import { ParentFolderFinder } from '../../../../context/virtual-drive/folders/application/ParentFolderFinder'; import { FolderPathUpdater } from '../../../../context/virtual-drive/folders/application/FolderPathUpdater'; import { FolderRepositoryInitializer } from '../../../../context/virtual-drive/folders/application/FolderRepositoryInitializer'; import { FoldersPlaceholderCreator } from '../../../../context/virtual-drive/folders/application/FoldersPlaceholderCreator'; @@ -15,11 +14,10 @@ import { FolderPlaceholderUpdater } from '../../../../context/virtual-drive/fold export interface FoldersContainer { folderCreator: FolderCreatorFromOfflineFolder; - folderFinder: FolderFinder; + parentFolderFinder: ParentFolderFinder; folderDeleter: FolderDeleter; allParentFoldersStatusIsExists: AllParentFoldersStatusIsExists; folderPathUpdater: FolderPathUpdater; - folderByPartialSearcher: FolderByPartialSearcher; synchronizeOfflineModificationsOnFolderCreated: SynchronizeOfflineModificationsOnFolderCreated; offline: { folderCreator: OfflineFolderCreator; diff --git a/src/apps/sync-engine/dependency-injection/folders/builder.ts b/src/apps/sync-engine/dependency-injection/folders/builder.ts index 0534aa5ff..295d11f83 100644 --- a/src/apps/sync-engine/dependency-injection/folders/builder.ts +++ b/src/apps/sync-engine/dependency-injection/folders/builder.ts @@ -1,8 +1,7 @@ import { AllParentFoldersStatusIsExists } from '../../../../context/virtual-drive/folders/application/AllParentFoldersStatusIsExists'; -import { FolderByPartialSearcher } from '../../../../context/virtual-drive/folders/application/FolderByPartialSearcher'; import { FolderCreatorFromOfflineFolder } from '../../../../context/virtual-drive/folders/application/FolderCreatorFromOfflineFolder'; import { FolderDeleter } from '../../../../context/virtual-drive/folders/application/FolderDeleter'; -import { FolderFinder } from '../../../../context/virtual-drive/folders/application/FolderFinder'; +import { ParentFolderFinder } from '../../../../context/virtual-drive/folders/application/ParentFolderFinder'; import { FolderMover } from '../../../../context/virtual-drive/folders/application/FolderMover'; import { FolderPathUpdater } from '../../../../context/virtual-drive/folders/application/FolderPathUpdater'; import { FolderRenamer } from '../../../../context/virtual-drive/folders/application/FolderRenamer'; @@ -50,7 +49,7 @@ export async function buildFoldersContainer( clients.newDrive ); - const folderFinder = new FolderFinder(repository); + const parentFolderFinder = new ParentFolderFinder(repository); const allParentFoldersStatusIsExists = new AllParentFoldersStatusIsExists( repository @@ -73,7 +72,7 @@ export async function buildFoldersContainer( const folderMover = new FolderMover( repository, remoteFileSystem, - folderFinder + parentFolderFinder ); const folderRenamer = new FolderRenamer( repository, @@ -82,8 +81,6 @@ export async function buildFoldersContainer( syncFolderMessenger ); - const folderByPartialSearcher = new FolderByPartialSearcher(repository); - const folderPathUpdater = new FolderPathUpdater( repository, folderMover, @@ -92,14 +89,14 @@ export async function buildFoldersContainer( const offlineRepository = new InMemoryOfflineFolderRepository(); const offlineFolderCreator = new OfflineFolderCreator( - folderFinder, + parentFolderFinder, offlineRepository, repository ); const offlineFolderMover = new OfflineFolderMover( offlineRepository, - folderFinder + parentFolderFinder ); const offlineFolderRenamer = new OfflineFolderRenamer(offlineRepository); const offlineFolderPathUpdater = new OfflineFolderPathUpdater( @@ -133,11 +130,10 @@ export async function buildFoldersContainer( return { folderCreator, - folderFinder, + parentFolderFinder, folderDeleter, allParentFoldersStatusIsExists: allParentFoldersStatusIsExists, folderPathUpdater, - folderByPartialSearcher, synchronizeOfflineModificationsOnFolderCreated, offline: { folderCreator: offlineFolderCreator, diff --git a/src/context/shared/domain/DownloadProgressTracker.ts b/src/context/shared/domain/DownloadProgressTracker.ts index eeaf9799d..5a83e3d53 100644 --- a/src/context/shared/domain/DownloadProgressTracker.ts +++ b/src/context/shared/domain/DownloadProgressTracker.ts @@ -9,7 +9,6 @@ export interface DownloadProgressTracker { percentage: number; } ): Promise; - downloadFinished( name: string, extension: string, @@ -18,6 +17,5 @@ export interface DownloadProgressTracker { elapsedTime: number; } ): Promise; - error(name: string, extension: string): Promise; } diff --git a/src/context/virtual-drive/files/application/FileCreator.ts b/src/context/virtual-drive/files/application/FileCreator.ts index 64ceac690..b6b7e5220 100644 --- a/src/context/virtual-drive/files/application/FileCreator.ts +++ b/src/context/virtual-drive/files/application/FileCreator.ts @@ -1,4 +1,3 @@ -import { FolderFinder } from '../../folders/application/FolderFinder'; import { FilePath } from '../domain/FilePath'; import { File } from '../domain/File'; import { FileSize } from '../domain/FileSize'; @@ -12,12 +11,13 @@ import { SyncFileMessenger } from '../domain/SyncFileMessenger'; import { FileStatuses } from '../domain/FileStatus'; import { DriveDesktopError } from '../../../shared/domain/errors/DriveDesktopError'; import Logger from 'electron-log'; +import { ParentFolderFinder } from '../../folders/application/ParentFolderFinder'; export class FileCreator { constructor( private readonly remote: RemoteFileSystem, private readonly repository: FileRepository, - private readonly folderFinder: FolderFinder, + private readonly parentFolderFinder: ParentFolderFinder, private readonly fileDeleter: FileDeleter, private readonly eventBus: EventBus, private readonly notifier: SyncFileMessenger @@ -29,18 +29,22 @@ export class FileCreator { size: number ): Promise { try { - const existingFile = this.repository.searchByPartial({ + const existingFiles = this.repository.matchingPartial({ path: PlatformPathConverter.winToPosix(filePath.value), status: FileStatuses.EXISTS, }); - if (existingFile) { - await this.fileDeleter.run(existingFile.contentsId); + if (existingFiles) { + await Promise.all( + existingFiles.map((existingFile) => + this.fileDeleter.run(existingFile.contentsId) + ) + ); } const fileSize = new FileSize(size); - const folder = this.folderFinder.findFromFilePath(filePath); + const folder = await this.parentFolderFinder.run(filePath); const offline = OfflineFile.create( contentsId, diff --git a/src/context/virtual-drive/files/application/FileDeleter.ts b/src/context/virtual-drive/files/application/FileDeleter.ts index 7044ae795..5f4180738 100644 --- a/src/context/virtual-drive/files/application/FileDeleter.ts +++ b/src/context/virtual-drive/files/application/FileDeleter.ts @@ -18,10 +18,7 @@ export class FileDeleter { ) {} async run(contentsId: File['contentsId']): Promise { - const file = this.repository.searchByPartial({ - contentsId, - status: FileStatuses.EXISTS, - }); + const file = await this.repository.searchByContentsId(contentsId); if (!file) { return; @@ -32,7 +29,7 @@ export class FileDeleter { return; } - const allParentsExists = this.allParentFoldersStatusIsExists.run( + const allParentsExists = await this.allParentFoldersStatusIsExists.run( file.folderId ); diff --git a/src/context/virtual-drive/files/application/FileFinderByContentsId.ts b/src/context/virtual-drive/files/application/FileFinderByContentsId.ts deleted file mode 100644 index e4eb8271d..000000000 --- a/src/context/virtual-drive/files/application/FileFinderByContentsId.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { FileNotFoundError } from '../domain/errors/FileNotFoundError'; -import { File } from '../domain/File'; -import { FileRepository } from '../domain/FileRepository'; - -export class FileFinderByContentsId { - constructor(private readonly repository: FileRepository) {} - - run(contentsId: string): File { - const file = this.repository.searchByPartial({ contentsId }); - - if (!file) { - throw new FileNotFoundError(contentsId); - } - - return file; - } -} diff --git a/src/context/virtual-drive/files/application/FilePathUpdater.ts b/src/context/virtual-drive/files/application/FilePathUpdater.ts index 683afa0b2..018bd459e 100644 --- a/src/context/virtual-drive/files/application/FilePathUpdater.ts +++ b/src/context/virtual-drive/files/application/FilePathUpdater.ts @@ -1,24 +1,26 @@ -import { ActionNotPermittedError } from '../domain/errors/ActionNotPermittedError'; -import { FileAlreadyExistsError } from '../domain/errors/FileAlreadyExistsError'; -import { FilePath } from '../domain/FilePath'; -import { File } from '../domain/File'; -import { FolderFinder } from '../../folders/application/FolderFinder'; +import Logger from 'electron-log'; +import { ParentFolderFinder } from '../../folders/application/ParentFolderFinder'; import { EventBus } from '../../shared/domain/EventBus'; +import { File } from '../domain/File'; +import { FilePath } from '../domain/FilePath'; import { FileRepository } from '../domain/FileRepository'; -import { RemoteFileSystem } from '../domain/file-systems/RemoteFileSystem'; -import { LocalFileSystem } from '../domain/file-systems/LocalFileSystem'; -import { FileRenameFailedDomainEvent } from '../domain/events/FileRenameFailedDomainEvent'; -import { FileRenameStartedDomainEvent } from '../domain/events/FileRenameStartedDomainEvent'; import { FileStatuses } from '../domain/FileStatus'; +import { ActionNotPermittedError } from '../domain/errors/ActionNotPermittedError'; +import { FileAlreadyExistsError } from '../domain/errors/FileAlreadyExistsError'; import { FileNotFoundError } from '../domain/errors/FileNotFoundError'; -import Logger from 'electron-log'; +import { FileRenameFailedDomainEvent } from '../domain/events/FileRenameFailedDomainEvent'; +import { FileRenameStartedDomainEvent } from '../domain/events/FileRenameStartedDomainEvent'; +import { LocalFileSystem } from '../domain/file-systems/LocalFileSystem'; +import { RemoteFileSystem } from '../domain/file-systems/RemoteFileSystem'; +import { SingleFileMatchingSearcher } from './SingleFileMatchingSearcher'; export class FilePathUpdater { constructor( private readonly remote: RemoteFileSystem, private readonly local: LocalFileSystem, private readonly repository: FileRepository, - private readonly folderFinder: FolderFinder, + private readonly singleFileMatching: SingleFileMatchingSearcher, + private readonly parentFolderFinder: ParentFolderFinder, private readonly eventBus: EventBus ) {} @@ -43,7 +45,7 @@ export class FilePathUpdater { private async move(file: File, destination: FilePath) { const trackerId = await this.local.getLocalFileId(file); - const destinationFolder = this.folderFinder.run(destination.dirname()); + const destinationFolder = await this.parentFolderFinder.run(destination); file.moveTo(destinationFolder, trackerId); @@ -56,7 +58,7 @@ export class FilePathUpdater { async run(contentsId: string, posixRelativePath: string) { const destination = new FilePath(posixRelativePath); - const file = this.repository.searchByPartial({ + const file = await this.singleFileMatching.run({ contentsId, status: FileStatuses.EXISTS, }); @@ -76,7 +78,7 @@ export class FilePathUpdater { return; } - const destinationFile = this.repository.searchByPartial({ + const destinationFile = this.repository.matchingPartial({ path: destination.value, status: FileStatuses.EXISTS, }); diff --git a/src/context/virtual-drive/files/application/FilePlaceholderCreatorFromContentsId.ts b/src/context/virtual-drive/files/application/FilePlaceholderCreatorFromContentsId.ts index 691aa35d0..3eada1c4a 100644 --- a/src/context/virtual-drive/files/application/FilePlaceholderCreatorFromContentsId.ts +++ b/src/context/virtual-drive/files/application/FilePlaceholderCreatorFromContentsId.ts @@ -1,15 +1,15 @@ import { File } from '../domain/File'; import { LocalFileSystem } from '../domain/file-systems/LocalFileSystem'; -import { FileFinderByContentsId } from './FileFinderByContentsId'; +import { SingleFileMatchingFinder } from './SingleFileMatchingFinder'; export class FilePlaceholderCreatorFromContentsId { constructor( - private readonly finder: FileFinderByContentsId, + private readonly finder: SingleFileMatchingFinder, private readonly local: LocalFileSystem ) {} - run(contentsId: File['contentsId']) { - const file = this.finder.run(contentsId); + async run(contentsId: File['contentsId']) { + const file = await this.finder.run({ contentsId }); this.local.createPlaceHolder(file); } diff --git a/src/context/virtual-drive/files/application/FilesByFolderPathSearcher.ts b/src/context/virtual-drive/files/application/FilesByFolderPathSearcher.ts index b23dc617e..9495338bc 100644 --- a/src/context/virtual-drive/files/application/FilesByFolderPathSearcher.ts +++ b/src/context/virtual-drive/files/application/FilesByFolderPathSearcher.ts @@ -1,4 +1,5 @@ -import { FolderFinder } from '../../folders/application/FolderFinder'; +import { ParentFolderFinder } from '../../folders/application/ParentFolderFinder'; +import { FolderPath } from '../../folders/domain/FolderPath'; import { File } from '../domain/File'; import { FileRepository } from '../domain/FileRepository'; import { FileStatuses } from '../domain/FileStatus'; @@ -6,13 +7,13 @@ import { FileStatuses } from '../domain/FileStatus'; export class FilesByFolderPathSearcher { constructor( private readonly repository: FileRepository, - private readonly folderFinder: FolderFinder + private readonly parentFolderFinder: ParentFolderFinder ) {} - async run(folderPath: string): Promise> { - const folder = this.folderFinder.run(folderPath); + async run(folderPath: FolderPath): Promise> { + const folder = await this.parentFolderFinder.run(folderPath); - const files = await this.repository.listByPartial({ + const files = this.repository.matchingPartial({ folderId: folder.id, status: FileStatuses.EXISTS, }); diff --git a/src/context/virtual-drive/files/application/FilesPlaceholderUpdater.ts b/src/context/virtual-drive/files/application/FilesPlaceholderUpdater.ts index a59899534..1f0d782cc 100644 --- a/src/context/virtual-drive/files/application/FilesPlaceholderUpdater.ts +++ b/src/context/virtual-drive/files/application/FilesPlaceholderUpdater.ts @@ -27,9 +27,7 @@ export class FilesPlaceholderUpdater { } private async update(remote: File): Promise { - const local = this.repository.searchByPartial({ - contentsId: remote.contentsId, - }); + const local = await this.repository.searchByContentsId(remote.contentsId); if (!local) { if (remote.status.is(FileStatuses.EXISTS)) { diff --git a/src/context/virtual-drive/files/application/FilesSearcher.ts b/src/context/virtual-drive/files/application/FirstsFileSearcher.ts similarity index 64% rename from src/context/virtual-drive/files/application/FilesSearcher.ts rename to src/context/virtual-drive/files/application/FirstsFileSearcher.ts index 42f9f5f64..94b6e14ca 100644 --- a/src/context/virtual-drive/files/application/FilesSearcher.ts +++ b/src/context/virtual-drive/files/application/FirstsFileSearcher.ts @@ -1,12 +1,14 @@ import { File, FileAttributes } from '../domain/File'; import { FileRepository } from '../domain/FileRepository'; -export class FilesSearcher { +export class FirstsFileSearcher { constructor(private readonly repository: FileRepository) {} async run(attributes: Partial): Promise { - const file = this.repository.searchByPartial(attributes); + const files = this.repository.matchingPartial(attributes); - return file; + if (!files) return; + + return files[0]; } } diff --git a/src/context/virtual-drive/files/application/SameFileWasMoved.ts b/src/context/virtual-drive/files/application/SameFileWasMoved.ts index 334e8d6e4..19b5f6a5a 100644 --- a/src/context/virtual-drive/files/application/SameFileWasMoved.ts +++ b/src/context/virtual-drive/files/application/SameFileWasMoved.ts @@ -1,23 +1,25 @@ +import Logger from 'electron-log'; import { EventRepository } from '../../shared/domain/EventRepository'; import { FilePath } from '../domain/FilePath'; -import { FileRepository } from '../domain/FileRepository'; +import { FileStatuses } from '../domain/FileStatus'; import { FileMovedDomainEvent } from '../domain/events/FileMovedDomainEvent'; -import Logger from 'electron-log'; import { LocalFileSystem } from '../domain/file-systems/LocalFileSystem'; +import { SingleFileMatchingSearcher } from './SingleFileMatchingSearcher'; // TODO: find a better name type WasMovedResult = { result: false } | { result: true; contentsId: string }; export class SameFileWasMoved { constructor( - private readonly repository: FileRepository, + private readonly singleFileSearcher: SingleFileMatchingSearcher, private readonly localFileSystem: LocalFileSystem, private readonly eventHistory: EventRepository ) {} async run(path: FilePath): Promise { - const fileInDestination = this.repository.searchByPartial({ + const fileInDestination = await this.singleFileSearcher.run({ path: path.value, + status: FileStatuses.EXISTS, }); if (!fileInDestination) { @@ -38,7 +40,7 @@ export class SameFileWasMoved { return { result: false }; } - const file = this.repository.searchByPartial({ + const file = await this.singleFileSearcher.run({ contentsId: movedEvent.aggregateId, }); diff --git a/src/context/virtual-drive/files/application/SingleFileMatchingFinder.ts b/src/context/virtual-drive/files/application/SingleFileMatchingFinder.ts new file mode 100644 index 000000000..bd6ff2955 --- /dev/null +++ b/src/context/virtual-drive/files/application/SingleFileMatchingFinder.ts @@ -0,0 +1,25 @@ +import { File, FileAttributes } from '../domain/File'; +import { FileRepository } from '../domain/FileRepository'; +import { FileNotFoundError } from '../domain/errors/FileNotFoundError'; +import { OnlyOneFileExpectedError } from '../domain/errors/OnlyOneFileExpectedError'; + +export class SingleFileMatchingFinder { + constructor(private readonly repository: FileRepository) {} + + /** + * @param partial a partial object of the attributes of the file in search + * @returns the matching file for the given partial attributes or undefined if no one matches + * @throws an {@link OnlyOneFileExpectedError} when it finds more than one file + * or a {@link FileNotFoundError} when no file is founded + */ + async run(partial: Partial): Promise { + const files = this.repository.matchingPartial(partial); + + if (files.length === 0) + throw new FileNotFoundError(JSON.stringify(partial)); + + if (files.length > 1) throw new OnlyOneFileExpectedError(); + + return files[0]; + } +} diff --git a/src/context/virtual-drive/files/application/SingleFileMatchingSearcher.ts b/src/context/virtual-drive/files/application/SingleFileMatchingSearcher.ts new file mode 100644 index 000000000..8cb0ece10 --- /dev/null +++ b/src/context/virtual-drive/files/application/SingleFileMatchingSearcher.ts @@ -0,0 +1,22 @@ +import { File, FileAttributes } from '../domain/File'; +import { FileRepository } from '../domain/FileRepository'; +import { OnlyOneFileExpectedError } from '../domain/errors/OnlyOneFileExpectedError'; + +export class SingleFileMatchingSearcher { + constructor(private readonly repository: FileRepository) {} + + /** + * @param partial a partial object of the attributes of the file in search + * @returns the matching file for the given partial attributes or undefined if no one matches + * @throws an {@link OnlyOneFileExpectedError} when it finds more than one file + */ + async run(attributes: Partial): Promise { + const files = this.repository.matchingPartial(attributes); + + if (files.length > 1) throw new OnlyOneFileExpectedError(); + + if (files.length === 0) return; + + return files[0]; + } +} diff --git a/src/context/virtual-drive/files/domain/FileRepository.ts b/src/context/virtual-drive/files/domain/FileRepository.ts index e08d455c1..ca5758196 100644 --- a/src/context/virtual-drive/files/domain/FileRepository.ts +++ b/src/context/virtual-drive/files/domain/FileRepository.ts @@ -3,9 +3,11 @@ import { File, FileAttributes } from './File'; export interface FileRepository { all(): Promise>; - searchByPartial(partial: Partial): File | undefined; + matchingPartial(partial: Partial): Array; - listByPartial(partial: Partial): Promise>; + searchById(id: File['id']): Promise; + + searchByContentsId(id: File['contentsId']): Promise; delete(id: File['contentsId']): Promise; diff --git a/src/context/virtual-drive/files/domain/errors/OnlyOneFileExpectedError.ts b/src/context/virtual-drive/files/domain/errors/OnlyOneFileExpectedError.ts new file mode 100644 index 000000000..200325333 --- /dev/null +++ b/src/context/virtual-drive/files/domain/errors/OnlyOneFileExpectedError.ts @@ -0,0 +1,5 @@ +export class OnlyOneFileExpectedError extends Error { + constructor() { + super('Expected to find only one file'); + } +} diff --git a/src/context/virtual-drive/files/infrastructure/InMemoryFileRepository.ts b/src/context/virtual-drive/files/infrastructure/InMemoryFileRepository.ts index 211bf871e..89d9c902a 100644 --- a/src/context/virtual-drive/files/infrastructure/InMemoryFileRepository.ts +++ b/src/context/virtual-drive/files/infrastructure/InMemoryFileRepository.ts @@ -2,7 +2,7 @@ import { File, FileAttributes } from '../domain/File'; import { FileRepository } from '../domain/FileRepository'; export class InMemoryFileRepository implements FileRepository { - private files: Map; + private files: Map; private get values(): Array { return Array.from(this.files.values()); @@ -17,36 +17,36 @@ export class InMemoryFileRepository implements FileRepository { } } - public all(): Promise> { - const files = [...this.files.values()].map((attributes) => - File.from(attributes) - ); - return Promise.resolve(files); - } + async searchById(id: number): Promise { + const files = this.files.values(); - searchByPartial(partial: Partial): File | undefined { - const keys = Object.keys(partial) as Array>; + for (const attributes of files) { + if (id === attributes.id) { + return File.from(attributes); + } + } - const file = this.values.find((attributes) => { - return keys.every((key: keyof FileAttributes) => { - if (key === 'contentsId') { - return ( - attributes[key].normalize() == (partial[key] as string).normalize() - ); - } + return undefined; + } - return attributes[key] == partial[key]; - }); - }); + async searchByContentsId(id: string): Promise { + const attributes = this.files.get(id); - if (file) { - return File.from(file); + if (!attributes) { + return; } - return undefined; + return File.from(attributes); + } + + public all(): Promise> { + const files = [...this.files.values()].map((attributes) => + File.from(attributes) + ); + return Promise.resolve(files); } - listByPartial(partial: Partial): Promise> { + matchingPartial(partial: Partial): Array { const keys = Object.keys(partial) as Array>; const filesAttributes = this.values.filter((attributes) => { @@ -61,9 +61,11 @@ export class InMemoryFileRepository implements FileRepository { }); }); - const files = filesAttributes.map((attributes) => File.from(attributes)); + if (!filesAttributes) { + return []; + } - return Promise.resolve(files); + return filesAttributes.map((attributes) => File.from(attributes)); } async delete(id: File['contentsId']): Promise { diff --git a/src/context/virtual-drive/folders/application/AllParentFoldersStatusIsExists.ts b/src/context/virtual-drive/folders/application/AllParentFoldersStatusIsExists.ts index fe5e1229c..65952a3ac 100644 --- a/src/context/virtual-drive/folders/application/AllParentFoldersStatusIsExists.ts +++ b/src/context/virtual-drive/folders/application/AllParentFoldersStatusIsExists.ts @@ -5,8 +5,8 @@ import { FolderStatuses } from '../domain/FolderStatus'; export class AllParentFoldersStatusIsExists { constructor(private readonly repository: FolderRepository) {} - run(id: Folder['id']): boolean { - const folder = this.repository.searchByPartial({ id }); + async run(id: Folder['id']): Promise { + const folder = await this.repository.searchById(id); if (!folder) { // TODO: investigate why when uploading a file in a path than previously existed returns undefined diff --git a/src/context/virtual-drive/folders/application/FolderByPartialSearcher.ts b/src/context/virtual-drive/folders/application/FolderByPartialSearcher.ts deleted file mode 100644 index 634d4573a..000000000 --- a/src/context/virtual-drive/folders/application/FolderByPartialSearcher.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Folder, FolderAttributes } from '../domain/Folder'; -import { FolderRepository } from '../domain/FolderRepository'; - -export class FolderByPartialSearcher { - constructor(private readonly repository: FolderRepository) {} - - run(partial: Partial): Folder | undefined { - return this.repository.searchByPartial(partial); - } -} diff --git a/src/context/virtual-drive/folders/application/FolderCreator.ts b/src/context/virtual-drive/folders/application/FolderCreator.ts index c7874bf5e..04757fa87 100644 --- a/src/context/virtual-drive/folders/application/FolderCreator.ts +++ b/src/context/virtual-drive/folders/application/FolderCreator.ts @@ -4,47 +4,43 @@ import { FolderCreatedAt } from '../domain/FolderCreatedAt'; import { FolderId } from '../domain/FolderId'; import { FolderPath } from '../domain/FolderPath'; import { FolderRepository } from '../domain/FolderRepository'; +import { FolderStatuses } from '../domain/FolderStatus'; import { FolderUpdatedAt } from '../domain/FolderUpdatedAt'; import { FolderUuid } from '../domain/FolderUuid'; -import { FolderAlreadyExists } from '../domain/errors/FolderAlreadyExists'; -import { FolderNotFoundError } from '../domain/errors/FolderNotFoundError'; +import { FolderInPathAlreadyExistsError } from '../domain/errors/FolderInPathAlreadyExistsError'; import { RemoteFileSystem } from '../domain/file-systems/RemoteFileSystem'; +import { ParentFolderFinder } from './ParentFolderFinder'; export class FolderCreator { constructor( private readonly repository: FolderRepository, + private readonly parentFolderFinder: ParentFolderFinder, private readonly remote: RemoteFileSystem, private readonly eventBus: EventBus ) {} - private ensureItDoesNotExists(path: FolderPath): void { - const folder = this.repository.searchByPartial({ path: path.value }); - - if (!folder) { - return; - } - - throw new FolderAlreadyExists(folder); - } - - private findParentId(path: FolderPath): FolderId { - const parent = this.repository.searchByPartial({ - path: path.dirname(), + private async ensureItDoesNotExists(path: FolderPath): Promise { + const result = this.repository.matchingPartial({ + path: path.value, + status: FolderStatuses.EXISTS, }); - if (!parent) { - throw new FolderNotFoundError(path.dirname()); + if (result.length > 0) { + throw new FolderInPathAlreadyExistsError(path); } + } + private async findParentId(path: FolderPath): Promise { + const parent = await this.parentFolderFinder.run(path); return new FolderId(parent.id); } async run(path: string): Promise { const folderPath = new FolderPath(path); - this.ensureItDoesNotExists(folderPath); + await this.ensureItDoesNotExists(folderPath); - const parentId = this.findParentId(folderPath); + const parentId = await this.findParentId(folderPath); const response = await this.remote.persist(folderPath, parentId); diff --git a/src/context/virtual-drive/folders/application/FolderDeleter.ts b/src/context/virtual-drive/folders/application/FolderDeleter.ts index 67cabbfc3..2c3fe5cc4 100644 --- a/src/context/virtual-drive/folders/application/FolderDeleter.ts +++ b/src/context/virtual-drive/folders/application/FolderDeleter.ts @@ -16,7 +16,7 @@ export class FolderDeleter { ) {} async run(uuid: Folder['uuid']): Promise { - const folder = this.repository.searchByPartial({ uuid }); + const folder = await this.repository.searchByUuid(uuid); if (!folder) { throw new FolderNotFoundError(uuid); @@ -27,7 +27,7 @@ export class FolderDeleter { throw new ActionNotPermittedError('Trash root folder'); } - const allParentsExists = this.allParentFoldersStatusIsExists.run( + const allParentsExists = await this.allParentFoldersStatusIsExists.run( // TODO: Create a new aggregate root for root folder so the rest have the parent Id as number folder.parentId as number ); diff --git a/src/context/virtual-drive/folders/application/FolderFinder.ts b/src/context/virtual-drive/folders/application/FolderFinder.ts deleted file mode 100644 index 8f50d9b46..000000000 --- a/src/context/virtual-drive/folders/application/FolderFinder.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { FilePath } from '../../files/domain/FilePath'; -import { FolderNotFoundError } from '../domain/errors/FolderNotFoundError'; -import { Folder } from '../domain/Folder'; -import { FolderRepository } from '../domain/FolderRepository'; - -export class FolderFinder { - constructor(private readonly repository: FolderRepository) {} - - run(path: string): Folder { - const folder = this.repository.searchByPartial({ path }); - - if (!folder) { - throw new FolderNotFoundError(path); - } - - return folder; - } - - findFromFilePath(path: FilePath): Folder { - const folder = this.repository.searchByPartial({ path: path.dirname() }); - - if (!folder) { - throw new FolderNotFoundError(path.dirname()); - } - - return folder; - } -} diff --git a/src/context/virtual-drive/folders/application/FolderMover.ts b/src/context/virtual-drive/folders/application/FolderMover.ts index f185e9fd8..20c0bc287 100644 --- a/src/context/virtual-drive/folders/application/FolderMover.ts +++ b/src/context/virtual-drive/folders/application/FolderMover.ts @@ -1,15 +1,16 @@ import { ActionNotPermittedError } from '../domain/errors/ActionNotPermittedError'; import { FolderPath } from '../domain/FolderPath'; import { Folder } from '../domain/Folder'; -import { FolderFinder } from './FolderFinder'; +import { ParentFolderFinder } from './ParentFolderFinder'; import { FolderRepository } from '../domain/FolderRepository'; import { RemoteFileSystem } from '../domain/file-systems/RemoteFileSystem'; +import { FolderStatuses } from '../domain/FolderStatus'; export class FolderMover { constructor( private readonly repository: FolderRepository, private readonly remote: RemoteFileSystem, - private readonly folderFinder: FolderFinder + private readonly fileParentFolderFinder: ParentFolderFinder ) {} private async move(folder: Folder, parentFolder: Folder) { @@ -20,17 +21,20 @@ export class FolderMover { } async run(folder: Folder, destination: FolderPath): Promise { - const resultFolder = this.repository.searchByPartial({ + const resultFolder = this.repository.matchingPartial({ path: destination.value, + status: FolderStatuses.EXISTS, }); - const shouldBeMerge = resultFolder !== undefined; + const shouldBeMerge = resultFolder.length > 0; if (shouldBeMerge) { throw new ActionNotPermittedError('overwrite'); } - const destinationFolder = this.folderFinder.run(destination.dirname()); + const destinationFolder = await this.fileParentFolderFinder.run( + destination + ); await this.move(folder, destinationFolder); } diff --git a/src/context/virtual-drive/folders/application/FolderPathUpdater.ts b/src/context/virtual-drive/folders/application/FolderPathUpdater.ts index 5245f593b..9487a0a3c 100644 --- a/src/context/virtual-drive/folders/application/FolderPathUpdater.ts +++ b/src/context/virtual-drive/folders/application/FolderPathUpdater.ts @@ -7,6 +7,7 @@ import { FolderNotFoundError } from '../domain/errors/FolderNotFoundError'; import { FolderMover } from './FolderMover'; import { FolderRenamer } from './FolderRenamer'; import { PathHasNotChangedError } from '../domain/errors/PathHasNotChangedError'; +import { FolderStatuses } from '../domain/FolderStatus'; export class FolderPathUpdater { constructor( @@ -16,7 +17,10 @@ export class FolderPathUpdater { ) {} async run(uuid: Folder['uuid'], posixRelativePath: string) { - const folder = this.repository.searchByPartial({ uuid }); + const folder = this.repository.matchingPartial({ + uuid, + status: FolderStatuses.EXISTS, + })[0]; if (!folder) { throw new FolderNotFoundError(uuid); diff --git a/src/context/virtual-drive/folders/application/FolderSearcher.ts b/src/context/virtual-drive/folders/application/FolderSearcher.ts deleted file mode 100644 index 924a65cb1..000000000 --- a/src/context/virtual-drive/folders/application/FolderSearcher.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Folder, FolderAttributes } from '../domain/Folder'; -import { FolderRepository } from '../domain/FolderRepository'; - -export class FolderSearcher { - constructor(private readonly repository: FolderRepository) {} - - run(partial: Partial): Promise { - const folder = this.repository.searchByPartial(partial); - - return Promise.resolve(folder); - } -} diff --git a/src/context/virtual-drive/folders/application/FoldersByParentPathLister.ts b/src/context/virtual-drive/folders/application/FoldersByParentPathLister.ts index dee1ba466..737cb3423 100644 --- a/src/context/virtual-drive/folders/application/FoldersByParentPathLister.ts +++ b/src/context/virtual-drive/folders/application/FoldersByParentPathLister.ts @@ -1,18 +1,19 @@ import { Folder } from '../domain/Folder'; +import { FolderPath } from '../domain/FolderPath'; import { FolderRepository } from '../domain/FolderRepository'; -import { FolderFinder } from './FolderFinder'; +import { ParentFolderFinder } from './ParentFolderFinder'; export class FoldersByParentPathLister { constructor( - private readonly folderFinder: FolderFinder, + private readonly parentFolderFinder: ParentFolderFinder, private readonly repository: FolderRepository ) {} - async run(path: string): Promise> { - const parent = this.folderFinder.run(path); + async run(folderPath: FolderPath): Promise> { + const parent = await this.parentFolderFinder.run(folderPath); - const folders = await this.repository.listByPartial({ - parentId: parent?.id, + const folders = this.repository.matchingPartial({ + parentId: parent.id, }); return folders.map((folder) => folder.name); diff --git a/src/context/virtual-drive/folders/application/Offline/OfflineFolderCreator.ts b/src/context/virtual-drive/folders/application/Offline/OfflineFolderCreator.ts index e1bfad328..5b2638a22 100644 --- a/src/context/virtual-drive/folders/application/Offline/OfflineFolderCreator.ts +++ b/src/context/virtual-drive/folders/application/Offline/OfflineFolderCreator.ts @@ -1,21 +1,21 @@ import { FolderPath } from '../../domain/FolderPath'; import { OfflineFolder } from '../../domain/OfflineFolder'; import { OfflineFolderRepository } from '../../domain/OfflineFolderRepository'; -import { FolderFinder } from '../FolderFinder'; +import { ParentFolderFinder } from '../ParentFolderFinder'; import { FolderRepository } from '../../domain/FolderRepository'; import { FolderId } from '../../domain/FolderId'; export class OfflineFolderCreator { constructor( - private readonly folderFinder: FolderFinder, + private readonly parentFolderFinder: ParentFolderFinder, private readonly offlineRepository: OfflineFolderRepository, private readonly repository: FolderRepository ) {} - run(posixRelativePath: string): OfflineFolder { + async run(posixRelativePath: string): Promise { const folderPath = new FolderPath(posixRelativePath); - const onlineFolder = this.repository.searchByPartial({ + const onlineFolder = this.repository.matchingPartial({ path: folderPath.value, }); @@ -23,7 +23,7 @@ export class OfflineFolderCreator { throw new Error('The folder already exists on remote'); } - const parent = this.folderFinder.run(folderPath.dirname()); + const parent = await this.parentFolderFinder.run(folderPath); const parentId = new FolderId(parent.id); diff --git a/src/context/virtual-drive/folders/application/Offline/OfflineFolderMover.ts b/src/context/virtual-drive/folders/application/Offline/OfflineFolderMover.ts index 21694eeeb..ad1c3e32d 100644 --- a/src/context/virtual-drive/folders/application/Offline/OfflineFolderMover.ts +++ b/src/context/virtual-drive/folders/application/Offline/OfflineFolderMover.ts @@ -2,12 +2,12 @@ import { FolderPath } from '../../domain/FolderPath'; import { OfflineFolder } from '../../domain/OfflineFolder'; import { OfflineFolderRepository } from '../../domain/OfflineFolderRepository'; import { ActionNotPermittedError } from '../../domain/errors/ActionNotPermittedError'; -import { FolderFinder } from '../FolderFinder'; +import { ParentFolderFinder } from '../ParentFolderFinder'; export class OfflineFolderMover { constructor( private readonly offlineFolderRepository: OfflineFolderRepository, - private readonly folderFinder: FolderFinder + private readonly parentFolderFinder: ParentFolderFinder ) {} async run(folder: OfflineFolder, destination: FolderPath) { @@ -21,7 +21,7 @@ export class OfflineFolderMover { throw new ActionNotPermittedError('overwrite'); } - const destinationFolder = this.folderFinder.run(destination.dirname()); + const destinationFolder = await this.parentFolderFinder.run(destination); folder.moveTo(destinationFolder); this.offlineFolderRepository.update(folder); diff --git a/src/context/virtual-drive/folders/application/ParentFolderFinder.ts b/src/context/virtual-drive/folders/application/ParentFolderFinder.ts new file mode 100644 index 000000000..e2e35c7e3 --- /dev/null +++ b/src/context/virtual-drive/folders/application/ParentFolderFinder.ts @@ -0,0 +1,26 @@ +import { Path } from '../../../shared/domain/value-objects/Path'; +import { FolderNotFoundError } from '../domain/errors/FolderNotFoundError'; +import { Folder } from '../domain/Folder'; +import { FolderRepository } from '../domain/FolderRepository'; +import { FolderStatuses } from '../domain/FolderStatus'; + +export class ParentFolderFinder { + constructor(private readonly repository: FolderRepository) {} + + async run(path: Path): Promise { + const result = this.repository.matchingPartial({ + path: path.dirname(), + status: FolderStatuses.EXISTS, + }); + + if (!result || result.length === 0) { + throw new FolderNotFoundError(path.dirname()); + } + + if (result.length > 1) { + throw new Error('A file can only have a parent'); + } + + return result[0]; + } +} diff --git a/src/context/virtual-drive/folders/application/SingleFolderMatchingFinder.ts b/src/context/virtual-drive/folders/application/SingleFolderMatchingFinder.ts new file mode 100644 index 000000000..75d8e7aaa --- /dev/null +++ b/src/context/virtual-drive/folders/application/SingleFolderMatchingFinder.ts @@ -0,0 +1,25 @@ +import { Folder, FolderAttributes } from '../domain/Folder'; +import { FolderRepository } from '../domain/FolderRepository'; +import { FolderNotFoundError } from '../domain/errors/FolderNotFoundError'; +import { OnlyOneFolderExpectedError } from '../domain/errors/OnlyOneFolderExpectedError'; + +export class SingleFolderMatchingFinder { + constructor(private readonly repository: FolderRepository) {} + + /** + * @param partial a partial object of the attributes of the folder in search + * @returns the matching folder for the given partial attributes + * @throws an {@link OnlyOneFolderExpectedError} if it finds more than one folder + * or a {@link FolderNotFoundError} if no folder is founded + */ + async run(partial: Partial): Promise { + const folders = this.repository.matchingPartial(partial); + + if (folders.length === 0) + throw new FolderNotFoundError(JSON.stringify(partial)); + + if (folders.length > 1) throw new OnlyOneFolderExpectedError(); + + return folders[0]; + } +} diff --git a/src/context/virtual-drive/folders/application/SingleFolderMatchingSearcher.ts b/src/context/virtual-drive/folders/application/SingleFolderMatchingSearcher.ts new file mode 100644 index 000000000..a459c6de9 --- /dev/null +++ b/src/context/virtual-drive/folders/application/SingleFolderMatchingSearcher.ts @@ -0,0 +1,22 @@ +import { Folder, FolderAttributes } from '../domain/Folder'; +import { FolderRepository } from '../domain/FolderRepository'; +import { OnlyOneFolderExpectedError } from '../domain/errors/OnlyOneFolderExpectedError'; + +export class SingleFolderMatchingSearcher { + constructor(private readonly repository: FolderRepository) {} + + /** + * @param partial a partial object of the attributes of the folder in search + * @returns the matching folder for the given partial attributes or undefined if no one matches + * @throws an {@link OnlyOneFolderExpectedError} when it finds more than one folder + */ + async run(partial: Partial): Promise { + const folders = this.repository.matchingPartial(partial); + + if (folders.length > 1) throw new OnlyOneFolderExpectedError(); + + if (folders.length === 0) return; + + return folders[0]; + } +} diff --git a/src/context/virtual-drive/folders/application/SynchronizeOfflineModifications.ts b/src/context/virtual-drive/folders/application/SynchronizeOfflineModifications.ts index fd5818b5a..85447c4b0 100644 --- a/src/context/virtual-drive/folders/application/SynchronizeOfflineModifications.ts +++ b/src/context/virtual-drive/folders/application/SynchronizeOfflineModifications.ts @@ -35,7 +35,7 @@ export class SynchronizeOfflineModifications { const rename = event as FolderRenamedDomainEvent; - const folder = this.repository.searchByPartial({ uuid }); + const folder = this.repository.matchingPartial({ uuid })[0]; if (!folder) { throw new FolderNotFoundError(uuid); diff --git a/src/context/virtual-drive/folders/application/UpdatePlaceholderFolder.ts b/src/context/virtual-drive/folders/application/UpdatePlaceholderFolder.ts index 9b06bd1b7..d665cd148 100644 --- a/src/context/virtual-drive/folders/application/UpdatePlaceholderFolder.ts +++ b/src/context/virtual-drive/folders/application/UpdatePlaceholderFolder.ts @@ -78,9 +78,9 @@ export class FolderPlaceholderUpdater { return; } - const local = this.repository.searchByPartial({ + const local = this.repository.matchingPartial({ uuid: remote.uuid, - }); + })[0]; if (!local) { if (remote.hasStatus(FolderStatuses.EXISTS)) { diff --git a/src/context/virtual-drive/folders/domain/Folder.ts b/src/context/virtual-drive/folders/domain/Folder.ts index 8c5001bb2..264f37c5b 100644 --- a/src/context/virtual-drive/folders/domain/Folder.ts +++ b/src/context/virtual-drive/folders/domain/Folder.ts @@ -9,6 +9,7 @@ import { FolderId } from './FolderId'; import { FolderCreatedAt } from './FolderCreatedAt'; import { FolderUpdatedAt } from './FolderUpdatedAt'; import { FolderMovedDomainEvent } from './events/FolderMovedDomainEvent'; +import { FolderAlreadyTrashed } from './errors/FolderAlreadyTrashed'; export type FolderAttributes = { id: number; @@ -185,6 +186,10 @@ export class Folder extends AggregateRoot { } trash() { + if (!this._status.is(FolderStatuses.EXISTS)) { + throw new FolderAlreadyTrashed(this.name); + } + this._status = this._status.changeTo(FolderStatuses.TRASHED); this._updatedAt = FolderUpdatedAt.now(); diff --git a/src/context/virtual-drive/folders/domain/FolderRepository.ts b/src/context/virtual-drive/folders/domain/FolderRepository.ts index fb27c56d0..eb8e701cc 100644 --- a/src/context/virtual-drive/folders/domain/FolderRepository.ts +++ b/src/context/virtual-drive/folders/domain/FolderRepository.ts @@ -3,9 +3,11 @@ import { Folder, FolderAttributes } from './Folder'; export interface FolderRepository { all(): Promise>; - searchByPartial(partial: Partial): Folder | undefined; + searchById(id: Folder['id']): Promise; - listByPartial(partial: Partial): Promise>; + searchByUuid(id: Folder['uuid']): Promise; + + matchingPartial(partial: Partial): Array; add(folder: Folder): Promise; diff --git a/src/context/virtual-drive/folders/domain/errors/FolderAlreadyExists.ts b/src/context/virtual-drive/folders/domain/errors/FolderAlreadyExists.ts deleted file mode 100644 index 976d6d879..000000000 --- a/src/context/virtual-drive/folders/domain/errors/FolderAlreadyExists.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Folder } from '../Folder'; - -export class FolderAlreadyExists extends Error { - constructor(folder: Folder) { - super(`Folder ${folder.path} already exists with id: ${folder.uuid}`); - } -} diff --git a/src/context/virtual-drive/folders/domain/errors/FolderAlreadyTrashed.ts b/src/context/virtual-drive/folders/domain/errors/FolderAlreadyTrashed.ts new file mode 100644 index 000000000..37d61b2c4 --- /dev/null +++ b/src/context/virtual-drive/folders/domain/errors/FolderAlreadyTrashed.ts @@ -0,0 +1,7 @@ +import { DriveDesktopError } from '../../../../shared/domain/errors/DriveDesktopError'; + +export class FolderAlreadyTrashed extends DriveDesktopError { + constructor(name: string) { + super('ACTION_NOT_PERMITTED', `Folder ${name} is already in the trash`); + } +} diff --git a/src/context/virtual-drive/folders/domain/errors/FolderInPathAlreadyExistsError.ts b/src/context/virtual-drive/folders/domain/errors/FolderInPathAlreadyExistsError.ts new file mode 100644 index 000000000..f482bcb8b --- /dev/null +++ b/src/context/virtual-drive/folders/domain/errors/FolderInPathAlreadyExistsError.ts @@ -0,0 +1,7 @@ +import { FolderPath } from '../FolderPath'; + +export class FolderInPathAlreadyExistsError extends Error { + constructor(path: FolderPath) { + super(`Folder in ${path.value} already exists`); + } +} diff --git a/src/context/virtual-drive/folders/domain/errors/OnlyOneFolderExpectedError.ts b/src/context/virtual-drive/folders/domain/errors/OnlyOneFolderExpectedError.ts new file mode 100644 index 000000000..7dd94f8d2 --- /dev/null +++ b/src/context/virtual-drive/folders/domain/errors/OnlyOneFolderExpectedError.ts @@ -0,0 +1,5 @@ +export class OnlyOneFolderExpectedError extends Error { + constructor() { + super('Expected to find only one folder'); + } +} diff --git a/src/context/virtual-drive/folders/infrastructure/InMemoryFolderRepository.ts b/src/context/virtual-drive/folders/infrastructure/InMemoryFolderRepository.ts index e2e2c8a28..4bde24569 100644 --- a/src/context/virtual-drive/folders/infrastructure/InMemoryFolderRepository.ts +++ b/src/context/virtual-drive/folders/infrastructure/InMemoryFolderRepository.ts @@ -20,36 +20,36 @@ export class InMemoryFolderRepository implements FolderRepository { return Promise.resolve(folders); } - searchByPartial(partial: Partial): Folder | undefined { - const keys = Object.keys(partial) as Array>; + async searchById(id: Folder['id']): Promise { + const attributes = this.folders.get(id); - const folder = this.values.find((attributes) => { - return keys.every( - (key: keyof FolderAttributes) => attributes[key] === partial[key] - ); - }); + if (!attributes) return; + + return Folder.from(attributes); + } + + async searchByUuid(id: Folder['uuid']): Promise { + const folders = this.folders.values(); - if (folder) { - return Folder.from(folder); + for (const attributes of folders) { + if (id === attributes.uuid) { + return Folder.from(attributes); + } } return undefined; } - listByPartial(partial: Partial): Promise { + matchingPartial(partial: Partial): Array { const keys = Object.keys(partial) as Array>; - const folderAttributes = this.values.filter((attributes) => { + const foldersAttributes = this.values.filter((attributes) => { return keys.every( (key: keyof FolderAttributes) => attributes[key] === partial[key] ); }); - const folders = folderAttributes.map((attributes) => - Folder.from(attributes) - ); - - return Promise.resolve(folders); + return foldersAttributes.map((attributes) => Folder.from(attributes)); } async add(folder: Folder): Promise { diff --git a/tests/context/virtual-drive/contents/infrastructure/download/EnvironmentContentFileDownloader.test.ts b/tests/context/virtual-drive/contents/infrastructure/download/EnvironmentContentFileDownloader.test.ts index 250ab819c..9c766c0f4 100644 --- a/tests/context/virtual-drive/contents/infrastructure/download/EnvironmentContentFileDownloader.test.ts +++ b/tests/context/virtual-drive/contents/infrastructure/download/EnvironmentContentFileDownloader.test.ts @@ -56,7 +56,13 @@ describe('Environment Content File Downloader', () => { await downloader.download(file); - expect(handler.mock.calls).toEqual([[25], [50], [75]]); + const firstArgumentsOfProgress = handler.mock.calls.map( + (args) => args[0] + ); + + expect(firstArgumentsOfProgress).toEqual( + expect.arrayContaining([25, 50, 75]) + ); }); it('emits an event when there is an error', async () => { @@ -78,5 +84,24 @@ describe('Environment Content File Downloader', () => { // no-op }); }); + + it('emits the error event before the promises fails', async () => { + const errorMsg = 'Error uploading file'; + const strategy = createDownloadStrategy((callbacks) => { + callbacks.finishedCallback( + { message: errorMsg } as unknown as Error, + Readable.from('') + ); + }); + + const downloader = new EnvironmentContentFileDownloader(strategy, bucket); + + const errorCallback = jest.fn(); + downloader.on('error', errorCallback); + + await downloader.download(file).catch(() => { + expect(errorCallback).toBeCalled(); + }); + }); }); }); diff --git a/tests/context/virtual-drive/files/__mocks__/FileRepositoryMock.ts b/tests/context/virtual-drive/files/__mocks__/FileRepositoryMock.ts index 519b31a89..0a2b7324c 100644 --- a/tests/context/virtual-drive/files/__mocks__/FileRepositoryMock.ts +++ b/tests/context/virtual-drive/files/__mocks__/FileRepositoryMock.ts @@ -1,4 +1,3 @@ -import { Nullable } from '../../../../../src/apps/shared/types/Nullable'; import { File, FileAttributes, @@ -7,8 +6,9 @@ import { FileRepository } from '../../../../../src/context/virtual-drive/files/d export class FileRepositoryMock implements FileRepository { public readonly allMock = jest.fn(); - public readonly searchByPartialMock = jest.fn(); - public readonly listByPartialMock = jest.fn(); + public readonly matchingPartialMock = jest.fn(); + public readonly searchByIdMock = jest.fn(); + public readonly searchByContentsIdMock = jest.fn(); public readonly deleteMock = jest.fn(); public readonly addMock = jest.fn(); public readonly updateMock = jest.fn(); @@ -16,18 +16,27 @@ export class FileRepositoryMock implements FileRepository { all(): Promise { return this.allMock(); } - searchByPartial(partial: Partial): Nullable { - return this.searchByPartialMock(partial); + + matchingPartial(partial: Partial): Array { + return this.matchingPartialMock(partial); + } + + searchById(id: number): Promise { + return this.searchByIdMock(id); } - listByPartial(partial: Partial): Promise { - return this.listByPartialMock(partial); + + searchByContentsId(id: string): Promise { + return this.searchByContentsIdMock(id); } + delete(id: string): Promise { return this.deleteMock(id); } + add(file: File): Promise { return this.addMock(file); } + update(file: File): Promise { return this.updateMock(file); } diff --git a/tests/context/virtual-drive/files/__test-class__/SingleFileMatchingTestClass.ts b/tests/context/virtual-drive/files/__test-class__/SingleFileMatchingTestClass.ts new file mode 100644 index 000000000..651be9e72 --- /dev/null +++ b/tests/context/virtual-drive/files/__test-class__/SingleFileMatchingTestClass.ts @@ -0,0 +1,18 @@ +import { SingleFileMatchingSearcher } from '../../../../../src/context/virtual-drive/files/application/SingleFileMatchingSearcher'; +import { + FileAttributes, + File, +} from '../../../../../src/context/virtual-drive/files/domain/File'; +import { FileRepository } from '../../../../../src/context/virtual-drive/files/domain/FileRepository'; + +export class SingleFileMatchingTestClass extends SingleFileMatchingSearcher { + public readonly mock = jest.fn(); + + constructor() { + super(undefined as unknown as FileRepository); + } + + run(attributes: Partial): Promise { + return this.mock(attributes); + } +} diff --git a/tests/context/virtual-drive/files/application/FileCreator.test.ts b/tests/context/virtual-drive/files/application/FileCreator.test.ts index 720122295..c1f015117 100644 --- a/tests/context/virtual-drive/files/application/FileCreator.test.ts +++ b/tests/context/virtual-drive/files/application/FileCreator.test.ts @@ -24,14 +24,14 @@ describe('File Creator', () => { remoteFileSystemMock = new RemoteFileSystemMock(); fileRepository = new FileRepositoryMock(); fileDeleter = FileDeleterFactory.deletionSuccess(); - const folderFinder = FolderFinderFactory.existingFolder(); + const parentFolderFinder = FolderFinderFactory.existingFolder(); eventBus = new EventBusMock(); notifier = new FileSyncNotifierMock(); SUT = new FileCreator( remoteFileSystemMock, fileRepository, - folderFinder, + parentFolderFinder, fileDeleter, eventBus, notifier @@ -95,9 +95,9 @@ describe('File Creator', () => { contentsId: contents.id, }).attributes(); - fileRepository.searchByPartialMock - .mockReturnValueOnce(existingFile) - .mockReturnValueOnce(existingFile); + fileRepository.matchingPartialMock + .mockReturnValueOnce([existingFile]) + .mockReturnValueOnce([existingFile]); const deleterSpy = jest .spyOn(fileDeleter, 'run') diff --git a/tests/context/virtual-drive/files/application/FileDeleter.test.ts b/tests/context/virtual-drive/files/application/FileDeleter.test.ts index d66a8f52f..aa4be0a1c 100644 --- a/tests/context/virtual-drive/files/application/FileDeleter.test.ts +++ b/tests/context/virtual-drive/files/application/FileDeleter.test.ts @@ -40,10 +40,10 @@ describe('File Deleter', () => { it('does not nothing if the file its not found', async () => { const contentsId = ContentsIdMother.raw(); - repository.searchByPartialMock.mockReturnValueOnce(undefined); + repository.searchByContentsIdMock.mockReturnValueOnce(undefined); jest .spyOn(allParentFoldersStatusIsExists, 'run') - .mockReturnValueOnce(false); + .mockResolvedValueOnce(false); await SUT.run(contentsId); @@ -53,10 +53,10 @@ describe('File Deleter', () => { it('does not delete a file if it has a parent already trashed', async () => { const file = FileMother.any(); - repository.searchByPartialMock.mockReturnValueOnce(file); + repository.searchByContentsIdMock.mockReturnValueOnce(file); jest .spyOn(allParentFoldersStatusIsExists, 'run') - .mockReturnValueOnce(false); + .mockResolvedValueOnce(false); await SUT.run(file.contentsId); @@ -66,8 +66,10 @@ describe('File Deleter', () => { it('trashes the file if it exists and does not have any parent trashed', async () => { const file = FileMother.any(); - repository.searchByPartialMock.mockReturnValueOnce(file); - jest.spyOn(allParentFoldersStatusIsExists, 'run').mockReturnValueOnce(true); + repository.searchByContentsIdMock.mockReturnValueOnce(file); + jest + .spyOn(allParentFoldersStatusIsExists, 'run') + .mockResolvedValueOnce(true); await SUT.run(file.contentsId); @@ -77,8 +79,10 @@ describe('File Deleter', () => { it('trashes the file with the status trashed', async () => { const file = FileMother.any(); - repository.searchByPartialMock.mockReturnValueOnce(file); - jest.spyOn(allParentFoldersStatusIsExists, 'run').mockReturnValueOnce(true); + repository.searchByContentsIdMock.mockReturnValueOnce(file); + jest + .spyOn(allParentFoldersStatusIsExists, 'run') + .mockResolvedValueOnce(true); await SUT.run(file.contentsId); diff --git a/tests/context/virtual-drive/files/application/FilePathUpdater.test.ts b/tests/context/virtual-drive/files/application/FilePathUpdater.test.ts index 68de50bd7..02100a829 100644 --- a/tests/context/virtual-drive/files/application/FilePathUpdater.test.ts +++ b/tests/context/virtual-drive/files/application/FilePathUpdater.test.ts @@ -1,17 +1,19 @@ import { FilePathUpdater } from '../../../../../src/context/virtual-drive/files/application/FilePathUpdater'; import { FilePath } from '../../../../../src/context/virtual-drive/files/domain/FilePath'; -import { FolderFinder } from '../../../../../src/context/virtual-drive/folders/application/FolderFinder'; -import { FolderFinderMock } from '../../folders/__mocks__/FolderFinderMock'; +import { ParentFolderFinder } from '../../../../../src/context/virtual-drive/folders/application/ParentFolderFinder'; +import { ParentFolderFinderTestClass } from '../../folders/__test-class__/ParentFolderFinderTestClass'; import { FolderMother } from '../../folders/domain/FolderMother'; import { EventBusMock } from '../../shared/__mock__/EventBusMock'; import { FileRepositoryMock } from '../__mocks__/FileRepositoryMock'; import { LocalFileSystemMock } from '../__mocks__/LocalFileSystemMock'; import { RemoteFileSystemMock } from '../__mocks__/RemoteFileSystemMock'; +import { SingleFileMatchingTestClass } from '../__test-class__/SingleFileMatchingTestClass'; import { FileMother } from '../domain/FileMother'; describe('File path updater', () => { let repository: FileRepositoryMock; - let folderFinder: FolderFinderMock; + let folderFinder: ParentFolderFinderTestClass; + let singleFileMatchingTestClass: SingleFileMatchingTestClass; let localFileSystem: LocalFileSystemMock; let eventBus: EventBusMock; let remoteFileSystemMock: RemoteFileSystemMock; @@ -19,7 +21,8 @@ describe('File path updater', () => { beforeEach(() => { repository = new FileRepositoryMock(); - folderFinder = new FolderFinderMock(); + folderFinder = new ParentFolderFinderTestClass(); + singleFileMatchingTestClass = new SingleFileMatchingTestClass(); eventBus = new EventBusMock(); remoteFileSystemMock = new RemoteFileSystemMock(); localFileSystem = new LocalFileSystemMock(); @@ -28,7 +31,8 @@ describe('File path updater', () => { remoteFileSystemMock, localFileSystem, repository, - folderFinder as unknown as FolderFinder, + singleFileMatchingTestClass, + folderFinder as unknown as ParentFolderFinder, eventBus ); }); @@ -37,7 +41,7 @@ describe('File path updater', () => { const fileToRename = FileMother.any(); const fileWithDestinationPath = undefined; - repository.searchByPartialMock + singleFileMatchingTestClass.mock .mockReturnValueOnce(fileToRename) .mockReturnValueOnce(fileWithDestinationPath); @@ -59,7 +63,7 @@ describe('File path updater', () => { const fileToRename = FileMother.any(); const fileWithDestinationPath = undefined; - repository.searchByPartialMock + singleFileMatchingTestClass.mock .mockReturnValueOnce(fileToRename) .mockReturnValueOnce(fileWithDestinationPath); @@ -77,7 +81,7 @@ describe('File path updater', () => { const fileInDestination = undefined; const localFileId = '1-2'; - repository.searchByPartialMock + singleFileMatchingTestClass.mock .mockReturnValueOnce(fileToMove) .mockReturnValueOnce(fileInDestination); diff --git a/tests/context/virtual-drive/folders/__mocks__/FolderFinderFactory.ts b/tests/context/virtual-drive/folders/__mocks__/FolderFinderFactory.ts index d7fd12d79..16de4120c 100644 --- a/tests/context/virtual-drive/folders/__mocks__/FolderFinderFactory.ts +++ b/tests/context/virtual-drive/folders/__mocks__/FolderFinderFactory.ts @@ -1,16 +1,16 @@ -import { FolderFinder } from '../../../../../src/context/virtual-drive/folders/application/FolderFinder'; +import { ParentFolderFinder } from '../../../../../src/context/virtual-drive/folders/application/ParentFolderFinder'; import { Folder } from '../../../../../src/context/virtual-drive/folders/domain/Folder'; import { FolderMother } from '../domain/FolderMother'; import { FolderRepositoryMock } from './FolderRepositoryMock'; export class FolderFinderFactory { - static existingFolder(folder?: Folder): FolderFinder { + static existingFolder(folder?: Folder): ParentFolderFinder { const repository = new FolderRepositoryMock(); const resolved = folder || FolderMother.any(); - repository.searchByPartialMock.mockResolvedValueOnce(resolved); + repository.matchingPartialMock.mockReturnValueOnce([resolved]); - return new FolderFinder(repository); + return new ParentFolderFinder(repository); } } diff --git a/tests/context/virtual-drive/folders/__mocks__/FolderFinderMock.ts b/tests/context/virtual-drive/folders/__mocks__/FolderFinderMock.ts deleted file mode 100644 index e21b4da9b..000000000 --- a/tests/context/virtual-drive/folders/__mocks__/FolderFinderMock.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { FolderFinder } from '../../../../../src/context/virtual-drive/folders/application/FolderFinder'; -import { FolderRepository } from '../../../../../src/context/virtual-drive/folders/domain/FolderRepository'; - -export class FolderFinderMock extends FolderFinder { - constructor() { - super({} as FolderRepository); - } - - public mock = jest.fn(); - - run(path: string) { - return this.mock(path); - } -} diff --git a/tests/context/virtual-drive/folders/__mocks__/FolderMoverMock.ts b/tests/context/virtual-drive/folders/__mocks__/FolderMoverMock.ts index b7cb996ab..e719ea1db 100644 --- a/tests/context/virtual-drive/folders/__mocks__/FolderMoverMock.ts +++ b/tests/context/virtual-drive/folders/__mocks__/FolderMoverMock.ts @@ -1,13 +1,17 @@ import { RemoteFileSystem } from '../../../../../src/context/virtual-drive/folders/domain/file-systems/RemoteFileSystem'; -import { FolderFinder } from '../../../../../src/context/virtual-drive/folders/application/FolderFinder'; import { FolderMover } from '../../../../../src/context/virtual-drive/folders/application/FolderMover'; import { FolderRepository } from '../../../../../src/context/virtual-drive/folders/domain/FolderRepository'; import { FolderPath } from '../../../../../src/context/virtual-drive/folders/domain/FolderPath'; import { Folder } from '../../../../../src/context/virtual-drive/folders/domain/Folder'; +import { ParentFolderFinder } from '../../../../../src/context/virtual-drive/folders/application/ParentFolderFinder'; export class FolderMoverMock extends FolderMover { constructor() { - super({} as FolderRepository, {} as RemoteFileSystem, {} as FolderFinder); + super( + {} as FolderRepository, + {} as RemoteFileSystem, + {} as ParentFolderFinder + ); } public readonly mock = jest.fn(); diff --git a/tests/context/virtual-drive/folders/__mocks__/FolderRepositoryMock.ts b/tests/context/virtual-drive/folders/__mocks__/FolderRepositoryMock.ts index c24ed74d1..3f0508b31 100644 --- a/tests/context/virtual-drive/folders/__mocks__/FolderRepositoryMock.ts +++ b/tests/context/virtual-drive/folders/__mocks__/FolderRepositoryMock.ts @@ -6,18 +6,28 @@ import { FolderRepository } from '../../../../../src/context/virtual-drive/folde export class FolderRepositoryMock implements FolderRepository { public readonly allMock = jest.fn(); - public readonly searchByPartialMock = jest.fn(); + public readonly matchingPartialMock = jest.fn(); public readonly listByPartialMock = jest.fn(); public readonly addMock = jest.fn(); public readonly deleteMock = jest.fn(); public readonly updateMock = jest.fn(); + public readonly searchByIdMock = jest.fn(); + public readonly searchByUuidMock = jest.fn(); all(): Promise { return this.allMock(); } - searchByPartial(partial: Partial): Folder | undefined { - return this.searchByPartialMock(partial); + searchById(id: number): Promise { + return this.searchByIdMock(id); + } + + searchByUuid(id: string): Promise { + return this.searchByUuidMock(id); + } + + matchingPartial(partial: Partial): Array { + return this.matchingPartialMock(partial); } listByPartial(partial: Partial): Promise> { diff --git a/tests/context/virtual-drive/folders/__test-class__/ParentFolderFinderTestClass.ts b/tests/context/virtual-drive/folders/__test-class__/ParentFolderFinderTestClass.ts new file mode 100644 index 000000000..7f075c59a --- /dev/null +++ b/tests/context/virtual-drive/folders/__test-class__/ParentFolderFinderTestClass.ts @@ -0,0 +1,15 @@ +import { Path } from '../../../../../src/context/shared/domain/value-objects/Path'; +import { ParentFolderFinder } from '../../../../../src/context/virtual-drive/folders/application/ParentFolderFinder'; +import { FolderRepository } from '../../../../../src/context/virtual-drive/folders/domain/FolderRepository'; + +export class ParentFolderFinderTestClass extends ParentFolderFinder { + constructor() { + super({} as FolderRepository); + } + + public mock = jest.fn(); + + run(path: Path) { + return this.mock(path); + } +} diff --git a/tests/context/virtual-drive/folders/application/FolderCreator.test.ts b/tests/context/virtual-drive/folders/application/FolderCreator.test.ts new file mode 100644 index 000000000..c64d92679 --- /dev/null +++ b/tests/context/virtual-drive/folders/application/FolderCreator.test.ts @@ -0,0 +1,152 @@ +import { InvalidArgumentError } from '../../../../../src/context/shared/domain/errors/InvalidArgumentError'; +import { FolderCreator } from '../../../../../src/context/virtual-drive/folders/application/FolderCreator'; +import { ParentFolderFinder } from '../../../../../src/context/virtual-drive/folders/application/ParentFolderFinder'; +import { Folder } from '../../../../../src/context/virtual-drive/folders/domain/Folder'; +import { FolderId } from '../../../../../src/context/virtual-drive/folders/domain/FolderId'; +import { FolderStatuses } from '../../../../../src/context/virtual-drive/folders/domain/FolderStatus'; +import { FolderInPathAlreadyExistsError } from '../../../../../src/context/virtual-drive/folders/domain/errors/FolderInPathAlreadyExistsError'; +import { FolderNotFoundError } from '../../../../../src/context/virtual-drive/folders/domain/errors/FolderNotFoundError'; +import { FolderPersistedDto } from '../../../../../src/context/virtual-drive/folders/domain/file-systems/RemoteFileSystem'; +import { EventBusMock } from '../../shared/__mock__/EventBusMock'; +import { FolderRemoteFileSystemMock } from '../__mocks__/FolderRemoteFileSystemMock'; +import { FolderRepositoryMock } from '../__mocks__/FolderRepositoryMock'; +import { FolderMother } from '../domain/FolderMother'; +import { FolderPathMother } from '../domain/FolderPathMother'; + +describe('Folder Creator', () => { + let repository: FolderRepositoryMock; + let remote: FolderRemoteFileSystemMock; + let eventBus: EventBusMock; + + let SUT: FolderCreator; + + beforeEach(() => { + repository = new FolderRepositoryMock(); + remote = new FolderRemoteFileSystemMock(); + eventBus = new EventBusMock(); + + const parentFolderFinder = new ParentFolderFinder(repository); + + SUT = new FolderCreator(repository, parentFolderFinder, remote, eventBus); + }); + + const mockCorrectPersistance = (folder: Folder) => { + remote.persistMock.mockResolvedValueOnce({ + id: folder.id, + uuid: folder.uuid, + createdAt: folder.createdAt.toISOString(), + updatedAt: folder.updatedAt.toISOString(), + parentId: folder.parentId as number, + } satisfies FolderPersistedDto); + }; + + it('throws an InvalidArgument error if the path is not a valid posix path', async () => { + const nonPosixPath = 'C:\\Users\\Internxt'; + + try { + await SUT.run(nonPosixPath); + fail('Expected InvalidArgumentError, but no error was thrown.'); + } catch (err) { + expect(err).toBeInstanceOf(InvalidArgumentError); + } + }); + + it('throws a FolderInPathAlreadyExists error if there is a folder on the desired path', async () => { + const path = FolderPathMother.any().value; + const folder = FolderMother.fromPartial({ + path, + status: FolderStatuses.EXISTS, + }); + + repository.matchingPartialMock.mockReturnValueOnce([folder]); + + try { + await SUT.run(path); + fail('Expected FolderInPathAlreadyExistsError, but no error was thrown.'); + } catch (err) { + expect(err).toBeInstanceOf(FolderInPathAlreadyExistsError); + } + }); + + it('throws a FolderNotFounded error if the parent folder is not founded', async () => { + const path = FolderPathMother.any().value; + + repository.matchingPartialMock + .mockReturnValueOnce([]) + .mockReturnValueOnce([]); + + try { + await SUT.run(path); + fail('Expected FolderNotFoundError, but no error was thrown.'); + } catch (err) { + expect(err).toBeInstanceOf(FolderNotFoundError); + } + }); + + it('persists a folder in the remote fs when the parent folder is found and the path is available', async () => { + const path = FolderPathMother.any(); + const parent = FolderMother.fromPartial({ path: path.dirname() }); + const folderCreated = FolderMother.fromPartial({ + path: path.value, + parentId: parent.id, + }); + + mockCorrectPersistance(folderCreated); + + repository.matchingPartialMock + .mockReturnValueOnce([]) + .mockReturnValueOnce([parent]); + + await SUT.run(path.value); + + expect(remote.persistMock).toBeCalledWith( + path, + new FolderId(parent.id), + undefined // optional parameter + ); + }); + + it('add the folder to the repository', async () => { + const path = FolderPathMother.any(); + const parent = FolderMother.fromPartial({ path: path.dirname() }); + const folderCreated = FolderMother.fromPartial({ + path: path.value, + parentId: parent.id, + }); + + mockCorrectPersistance(folderCreated); + + repository.matchingPartialMock + .mockReturnValueOnce([]) + .mockReturnValueOnce([parent]); + + await SUT.run(path.value); + + expect(repository.addMock).toBeCalledWith( + expect.objectContaining(folderCreated) + ); + }); + + it('publishes folder created event', async () => { + const path = FolderPathMother.any(); + const parent = FolderMother.fromPartial({ path: path.dirname() }); + const folderCreated = FolderMother.fromPartial({ + path: path.value, + parentId: parent.id, + }); + + mockCorrectPersistance(folderCreated); + + repository.matchingPartialMock + .mockReturnValueOnce([]) + .mockReturnValueOnce([parent]); + + await SUT.run(path.value); + + expect(eventBus.publishMock).toBeCalledWith( + expect.arrayContaining([ + expect.objectContaining({ aggregateId: folderCreated.uuid }), + ]) + ); + }); +}); diff --git a/tests/context/virtual-drive/folders/application/FolderDeleter.test.ts b/tests/context/virtual-drive/folders/application/FolderDeleter.test.ts index 451086e4a..a459a12f5 100644 --- a/tests/context/virtual-drive/folders/application/FolderDeleter.test.ts +++ b/tests/context/virtual-drive/folders/application/FolderDeleter.test.ts @@ -1,5 +1,6 @@ import { AllParentFoldersStatusIsExists } from '../../../../../src/context/virtual-drive/folders/application/AllParentFoldersStatusIsExists'; import { FolderDeleter } from '../../../../../src/context/virtual-drive/folders/application/FolderDeleter'; +import { FolderAlreadyTrashed } from '../../../../../src/context/virtual-drive/folders/domain/errors/FolderAlreadyTrashed'; import { FolderLocalFileSystemMock } from '../__mocks__/FolderLocalFileSystemMock'; import { FolderRemoteFileSystemMock } from '../__mocks__/FolderRemoteFileSystemMock'; import { FolderRepositoryMock } from '../__mocks__/FolderRepositoryMock'; @@ -31,8 +32,10 @@ describe('Folder deleter', () => { it('trashes an existing folder', async () => { const folder = FolderMother.exists(); - repository.searchByPartialMock.mockReturnValueOnce(folder); - jest.spyOn(allParentFoldersStatusIsExists, 'run').mockReturnValueOnce(true); + repository.searchByUuidMock.mockResolvedValueOnce(folder); + jest + .spyOn(allParentFoldersStatusIsExists, 'run') + .mockResolvedValueOnce(true); await SUT.run(folder.uuid); @@ -42,23 +45,26 @@ describe('Folder deleter', () => { it('throws an error when trashing a folder already trashed', async () => { const folder = FolderMother.trashed(); - repository.searchByPartialMock.mockReturnValueOnce(folder); - jest.spyOn(allParentFoldersStatusIsExists, 'run').mockReturnValueOnce(true); + repository.searchByUuidMock.mockResolvedValueOnce(folder); + jest + .spyOn(allParentFoldersStatusIsExists, 'run') + .mockResolvedValueOnce(true); await SUT.run(folder.uuid).catch((err) => { expect(err).toBeDefined(); + expect(err).toBeInstanceOf(FolderAlreadyTrashed); }); expect(repository.deleteMock).not.toBeCalled(); }); - it('does not delete the folder if a higher folder is already deleted ', async () => { + it('does not delete the folder if a higher folder is already trashed ', async () => { const folder = FolderMother.exists(); - repository.searchByPartialMock.mockReturnValueOnce(folder); + repository.searchByUuidMock.mockResolvedValueOnce(folder); jest .spyOn(allParentFoldersStatusIsExists, 'run') - .mockReturnValueOnce(false); + .mockResolvedValueOnce(false); await SUT.run(folder.uuid).catch((err) => { expect(err).toBeDefined(); @@ -70,8 +76,10 @@ describe('Folder deleter', () => { it('recreates the placeholder if the deletion fails', async () => { const folder = FolderMother.exists(); - repository.searchByPartialMock.mockReturnValueOnce(folder); - jest.spyOn(allParentFoldersStatusIsExists, 'run').mockReturnValueOnce(true); + repository.searchByUuidMock.mockResolvedValueOnce(folder); + jest + .spyOn(allParentFoldersStatusIsExists, 'run') + .mockResolvedValueOnce(true); remote.trashMock.mockRejectedValue(new Error('Error during the deletion')); await SUT.run(folder.uuid); diff --git a/tests/context/virtual-drive/folders/application/FolderMover.test.ts b/tests/context/virtual-drive/folders/application/FolderMover.test.ts index 93ae06223..57f6a973a 100644 --- a/tests/context/virtual-drive/folders/application/FolderMover.test.ts +++ b/tests/context/virtual-drive/folders/application/FolderMover.test.ts @@ -1,4 +1,4 @@ -import { FolderFinder } from '../../../../../src/context/virtual-drive/folders/application/FolderFinder'; +import { ParentFolderFinder } from '../../../../../src/context/virtual-drive/folders/application/ParentFolderFinder'; import { FolderMover } from '../../../../../src/context/virtual-drive/folders/application/FolderMover'; import { FolderPath } from '../../../../../src/context/virtual-drive/folders/domain/FolderPath'; import { FolderRemoteFileSystemMock } from '../__mocks__/FolderRemoteFileSystemMock'; @@ -7,24 +7,27 @@ import { FolderMother } from '../domain/FolderMother'; describe('Folder Mover', () => { let repository: FolderRepositoryMock; - let folderFinder: FolderFinder; + let folderFinder: ParentFolderFinder; let remoteFileSystem: FolderRemoteFileSystemMock; let SUT: FolderMover; beforeEach(() => { repository = new FolderRepositoryMock(); - folderFinder = new FolderFinder(repository); + folderFinder = new ParentFolderFinder(repository); remoteFileSystem = new FolderRemoteFileSystemMock(); SUT = new FolderMover(repository, remoteFileSystem, folderFinder); }); it('Folders cannot be overwrite', async () => { - const folder = FolderMother.in(1, '/folderA/folderB'); + const folder = FolderMother.fromPartial({ + parentId: 1, + path: '/folderA/folderB', + }); const destination = new FolderPath('/folderC/folderB'); - repository.searchByPartialMock.mockImplementation(() => - FolderMother.in(2, destination.value) + repository.matchingPartialMock.mockImplementation(() => + FolderMother.fromPartial({ parentId: 2, path: destination.value }) ); try { @@ -39,13 +42,19 @@ describe('Folder Mover', () => { describe('Move', () => { it('moves a folder when the destination folder does not contain a folder with the same folder', async () => { - const folder = FolderMother.in(1, '/folderA/folderB'); + const folder = FolderMother.fromPartial({ + parentId: 1, + path: '/folderA/folderB', + }); const destination = new FolderPath('/folderC/folderB'); - const folderC = FolderMother.in(2, '/folderC'); + const folderC = FolderMother.fromPartial({ + parentId: 2, + path: '/folderC', + }); - repository.searchByPartialMock - .mockReturnValueOnce(undefined) - .mockReturnValueOnce(folderC); + repository.matchingPartialMock + .mockReturnValueOnce([]) + .mockReturnValueOnce([folderC]); await SUT.run(folder, destination); diff --git a/tests/context/virtual-drive/folders/application/FolderPathUpdater.test.ts b/tests/context/virtual-drive/folders/application/FolderPathUpdater.test.ts index 3e9489748..212ddcb18 100644 --- a/tests/context/virtual-drive/folders/application/FolderPathUpdater.test.ts +++ b/tests/context/virtual-drive/folders/application/FolderPathUpdater.test.ts @@ -40,7 +40,7 @@ describe('Folder Path Updater', () => { it('throws a Folder Not Found Error if not folder is founded', async () => { const { uuid, destination } = provideInputs(); - repository.searchByPartialMock.mockReturnValueOnce(undefined); + repository.matchingPartialMock.mockReturnValueOnce([]); try { await folderPathUpdater.run(uuid, destination); @@ -53,7 +53,7 @@ describe('Folder Path Updater', () => { const folder = FolderMother.any(); const destination = FolderPathMother.any(); - repository.searchByPartialMock.mockReturnValueOnce(folder); + repository.matchingPartialMock.mockReturnValueOnce([folder]); try { await folderPathUpdater.run(folder.uuid, destination.value); @@ -66,7 +66,7 @@ describe('Folder Path Updater', () => { const folder = FolderMother.any(); const folderPathWithNewName = FolderPathMother.onFolder(folder.dirname); - repository.searchByPartialMock.mockReturnValueOnce(folder); + repository.matchingPartialMock.mockReturnValueOnce([folder]); await folderPathUpdater.run(folder.uuid, folderPathWithNewName.value); @@ -84,7 +84,7 @@ describe('Folder Path Updater', () => { folder.name + '(1)' ); - repository.searchByPartialMock.mockReturnValueOnce(folder); + repository.matchingPartialMock.mockReturnValueOnce([folder]); await folderPathUpdater.run(folder.uuid, desiredPath.value); @@ -98,7 +98,7 @@ describe('Folder Path Updater', () => { it('throws a Path Has Not Changed Error if the path desired path is the same as the current', async () => { const folder = FolderMother.any(); - repository.searchByPartialMock.mockReturnValueOnce(folder); + repository.matchingPartialMock.mockReturnValueOnce([folder]); try { await folderPathUpdater.run(folder.uuid, folder.path); diff --git a/tests/context/virtual-drive/folders/application/SynchronizeOfflineModifications.test.ts b/tests/context/virtual-drive/folders/application/SynchronizeOfflineModifications.test.ts index aa244ba35..04d1cb7ae 100644 --- a/tests/context/virtual-drive/folders/application/SynchronizeOfflineModifications.test.ts +++ b/tests/context/virtual-drive/folders/application/SynchronizeOfflineModifications.test.ts @@ -51,7 +51,7 @@ describe('Synchronize Offline Modifications', () => { await SUT.run(FolderUuid.random().value); - expect(repository.searchByPartialMock).not.toBeCalled(); + expect(repository.matchingPartialMock).not.toBeCalled(); }); it('throws an error if there is no folder with the given uuid', async () => { @@ -59,7 +59,7 @@ describe('Synchronize Offline Modifications', () => { .spyOn(offlineRepository, 'searchByPartial') .mockReturnValueOnce(OfflineFolderMother.random()); - repository.searchByPartialMock.mockReturnValueOnce(undefined); + repository.matchingPartialMock.mockReturnValueOnce(undefined); try { await SUT.run(FolderUuid.random().value); @@ -85,7 +85,7 @@ describe('Synchronize Offline Modifications', () => { .spyOn(offlineRepository, 'searchByPartial') .mockReturnValueOnce(offlineFolder); - repository.searchByPartialMock.mockReturnValueOnce(folder); + repository.matchingPartialMock.mockReturnValueOnce(folder); const renamerSpy = jest.spyOn(renamer, 'run'); @@ -112,7 +112,7 @@ describe('Synchronize Offline Modifications', () => { const renamerSpy = jest.spyOn(renamer, 'run'); - repository.searchByPartialMock.mockReturnValueOnce(folder); + repository.matchingPartialMock.mockReturnValueOnce([folder]); const event = new FolderRenamedDomainEvent({ aggregateId: offlineFolder.uuid, @@ -155,9 +155,9 @@ describe('Synchronize Offline Modifications', () => { const renamerSpy = jest.spyOn(renamer, 'run'); - repository.searchByPartialMock - .mockReturnValueOnce(afterCreation) - .mockReturnValueOnce(afterFirstRename); + repository.matchingPartialMock + .mockReturnValueOnce([afterCreation]) + .mockReturnValueOnce([afterFirstRename]); const uuid = offlineFolder.uuid; diff --git a/tests/context/virtual-drive/folders/domain/FolderMother.ts b/tests/context/virtual-drive/folders/domain/FolderMother.ts index c34d93704..8c67cf830 100644 --- a/tests/context/virtual-drive/folders/domain/FolderMother.ts +++ b/tests/context/virtual-drive/folders/domain/FolderMother.ts @@ -34,18 +34,6 @@ export class FolderMother { }); } - static in(folderId: number, path: string) { - return Folder.from({ - id: 20445, - uuid: FolderUuid.random().value, - path, - parentId: folderId, - updatedAt: new Date().toISOString(), - createdAt: new Date().toISOString(), - status: FolderStatuses.EXISTS, - }); - } - static withId(folderId: number) { return Folder.from({ id: folderId, diff --git a/yarn.lock b/yarn.lock index 4d49f0543..2b7ecb16d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1201,20 +1201,21 @@ glob "^7.1.6" minimatch "^3.0.4" -"@electron/get@^2.0.0": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@electron/get/-/get-2.0.3.tgz#fba552683d387aebd9f3fcadbcafc8e12ee4f960" - integrity sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ== +"@electron/get@^1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@electron/get/-/get-1.14.1.tgz#16ba75f02dffb74c23965e72d617adc721d27f40" + integrity sha512-BrZYyL/6m0ZXz/lDxy/nlVhQz+WF+iPS6qXolEU8atw7h6v1aYkjwJZ63m+bJMBTxDE66X+r2tPS4a/8C82sZw== dependencies: debug "^4.1.1" env-paths "^2.2.0" fs-extra "^8.1.0" - got "^11.8.5" + got "^9.6.0" progress "^2.0.3" semver "^6.2.0" sumchecker "^3.0.1" optionalDependencies: global-agent "^3.0.0" + global-tunnel-ng "^2.7.1" "@electron/universal@1.2.1": version "1.2.1" @@ -2188,6 +2189,11 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + "@sindresorhus/is@^4.0.0": version "4.6.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" @@ -2318,6 +2324,13 @@ "@svgr/plugin-jsx" "^6.5.1" "@svgr/plugin-svgo" "^6.5.1" +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + "@szmarczak/http-timer@^4.0.5": version "4.0.6" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" @@ -2735,12 +2748,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.32.tgz#5b5becc5da76fc055b2a601c8a3adbf13891227e" integrity sha512-zpnXe4dEz6PrWz9u7dqyRoq9VxwCvoXRPy/ewhmMa1CgEyVmtL1NJPQ2MX+4pf97vetquVKkpiMx0MwI8pjNOw== -"@types/node@^18.11.18": - version "18.19.14" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.14.tgz#1880ff1b3ac913f3877f711588e5ed227da01886" - integrity sha512-EnQ4Us2rmOS64nHDWr0XqAD8DsO6f3XR6lf9UIIrZQpUzPVdN/oPuEzfDWNHSyXLvoGgjuEm/sPwFGSSs35Wtg== - dependencies: - undici-types "~5.26.4" +"@types/node@^16.11.26": + version "16.18.83" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.83.tgz#681d1a20676d24fc47e2da3934536304097a81d8" + integrity sha512-TmBqzDY/GeCEmLob/31SunOQnqYE3ZiiuEh1U9o3HqE1E2cqKZQA5RQg4krEguCY3StnkXyDmCny75qyFLx/rA== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -2927,13 +2938,6 @@ dependencies: "@types/yargs-parser" "*" -"@types/yauzl@^2.9.1": - version "2.10.3" - resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.3.tgz#e9b2808b4f109504a03cda958259876f61017999" - integrity sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q== - dependencies: - "@types/node" "*" - "@typescript-eslint/eslint-plugin@^5.4.0", "@typescript-eslint/eslint-plugin@^5.51.0", "@typescript-eslint/eslint-plugin@^5.6.0", "@typescript-eslint/eslint-plugin@^5.8.1": version "5.59.11" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.11.tgz#8d466aa21abea4c3f37129997b198d141f09e76f" @@ -4018,6 +4022,19 @@ cacheable-lookup@^5.0.3: resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + cacheable-request@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" @@ -4415,6 +4432,16 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +concat-stream@^1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + concurrently@^6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-6.5.1.tgz#4518c67f7ac680cf5c34d5adf399a2a2047edc8c" @@ -4445,6 +4472,14 @@ conf@^10.2.0: pkg-up "^3.1.0" semver "^7.3.5" +config-chain@^1.1.11: + version "1.1.13" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" + integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + confusing-browser-globals@^1.0.10: version "1.0.11" resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" @@ -4759,7 +4794,7 @@ debounce@^1.2.1: resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== -debug@2.6.9, debug@^2.6.8: +debug@2.6.9, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -4808,6 +4843,13 @@ decode-uri-component@^0.2.2: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA== + dependencies: + mimic-response "^1.0.0" + decompress-response@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" @@ -4873,6 +4915,11 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" +defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== + defer-to-connect@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" @@ -5172,6 +5219,11 @@ duplexer2@^0.1.2: dependencies: readable-stream "^2.0.2" +duplexer3@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.5.tgz#0b5e4d7bad5de8901ea4440624c8e1d20099217e" + integrity sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA== + duplexer@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" @@ -5356,14 +5408,14 @@ electron-updater@^4.6.4: lodash.isequal "^4.5.0" semver "^7.3.5" -electron@^25.8.4: - version "25.9.8" - resolved "https://registry.yarnpkg.com/electron/-/electron-25.9.8.tgz#7c125ccbddad02861736275b0d4a387c59a91469" - integrity sha512-PGgp6PH46QVENHuAHc2NT1Su8Q1qov7qIl2jI5tsDpTibwV2zD8539AeWBQySeBU4dhbj9onIl7+1bXQ0wefBg== +electron@^19.1.9: + version "19.1.9" + resolved "https://registry.yarnpkg.com/electron/-/electron-19.1.9.tgz#01995eea4014f7cdb2f616f5f3492d4ed6f5e4f0" + integrity sha512-XT5LkTzIHB+ZtD3dTmNnKjVBWrDWReCKt9G1uAFLz6uJMEVcIUiYO+fph5pLXETiBw/QZBx8egduMEfIccLx+g== dependencies: - "@electron/get" "^2.0.0" - "@types/node" "^18.11.18" - extract-zip "^2.0.1" + "@electron/get" "^1.14.1" + "@types/node" "^16.11.26" + extract-zip "^1.0.3" emittery@^0.8.1: version "0.8.1" @@ -5390,7 +5442,7 @@ enabled@2.0.x: resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== -encodeurl@~1.0.2: +encodeurl@^1.0.2, encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== @@ -6069,16 +6121,15 @@ express@^4.17.3, express@^4.18.2: utils-merge "1.0.1" vary "~1.1.2" -extract-zip@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" - integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== +extract-zip@^1.0.3: + version "1.7.0" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927" + integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA== dependencies: - debug "^4.1.1" - get-stream "^5.1.0" + concat-stream "^1.6.2" + debug "^2.6.9" + mkdirp "^0.5.4" yauzl "^2.10.0" - optionalDependencies: - "@types/yauzl" "^2.9.1" extsprintf@^1.2.0: version "1.4.1" @@ -6443,6 +6494,13 @@ get-package-type@^0.1.0: resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + get-stream@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" @@ -6529,6 +6587,16 @@ global-agent@^3.0.0: semver "^7.3.2" serialize-error "^7.0.1" +global-tunnel-ng@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz#d03b5102dfde3a69914f5ee7d86761ca35d57d8f" + integrity sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg== + dependencies: + encodeurl "^1.0.2" + lodash "^4.17.10" + npm-conf "^1.1.3" + tunnel "^0.0.6" + globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -6598,7 +6666,7 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -got@^11.7.0, got@^11.8.5: +got@^11.7.0: version "11.8.6" resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== @@ -6615,6 +6683,23 @@ got@^11.7.0, got@^11.8.5: p-cancelable "^2.0.0" responselike "^2.0.0" +got@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" @@ -7024,6 +7109,11 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== +ini@^1.3.4: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + internal-slot@^1.0.3, internal-slot@^1.0.4, internal-slot@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" @@ -7976,6 +8066,11 @@ jsesc@~0.5.0: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ== + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -8105,6 +8200,13 @@ keyboardevents-areequal@^0.2.1: resolved "https://registry.yarnpkg.com/keyboardevents-areequal/-/keyboardevents-areequal-0.2.2.tgz#88191ec738ce9f7591c25e9056de928b40277194" integrity sha512-Nv+Kr33T0mEjxR500q+I6IWisOQ0lK1GGOncV0kWE6n4KFmpcu7RUX5/2B0EUtX51Cb0HjZ9VJsSY3u4cBa0kw== +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + keyv@^4.0.0: version "4.5.2" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.2.tgz#0e310ce73bf7851ec702f2eaf46ec4e3805cce56" @@ -8344,7 +8446,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== -lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: +lodash@^4.17.10, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -8410,6 +8512,11 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + lowercase-keys@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" @@ -8628,7 +8735,7 @@ mimic-fn@^3.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74" integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ== -mimic-response@^1.0.0: +mimic-response@^1.0.0, mimic-response@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== @@ -8761,7 +8868,7 @@ minizlib@^2.1.1, minizlib@^2.1.2: minipass "^3.0.0" yallist "^4.0.0" -mkdirp@^0.5.1, mkdirp@^0.5.5: +mkdirp@^0.5.1, mkdirp@^0.5.4, mkdirp@^0.5.5: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -8967,11 +9074,24 @@ normalize-range@^0.1.2: resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== +normalize-url@^4.1.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" + integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== + normalize-url@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== +npm-conf@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" + integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw== + dependencies: + config-chain "^1.1.11" + pify "^3.0.0" + npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -9170,6 +9290,11 @@ ora@^5.1.0: strip-ansi "^6.0.0" wcwidth "^1.0.1" +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + p-cancelable@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" @@ -9358,6 +9483,11 @@ pify@^2.3.0: resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== + pirates@^4.0.1, pirates@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" @@ -9704,6 +9834,11 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== + prettier-linter-helpers@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" @@ -9782,6 +9917,11 @@ prop-types@^15.6.2, prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -10051,7 +10191,7 @@ read-pkg@^6.0.0: parse-json "^5.2.0" type-fest "^1.0.1" -readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@~2.3.6: +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.2.2, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -10241,6 +10381,13 @@ resolve@^2.0.0-next.4: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ== + dependencies: + lowercase-keys "^1.0.0" + responselike@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" @@ -11257,6 +11404,11 @@ to-fast-properties@^2.0.0: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -11398,6 +11550,11 @@ tsutils@^3.21.0: dependencies: tslib "^1.8.1" +tunnel@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" + integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -11466,6 +11623,11 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== + typescript@^4.5.2: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" @@ -11486,11 +11648,6 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== - undici@^5.5.1: version "5.22.1" resolved "https://registry.yarnpkg.com/undici/-/undici-5.22.1.tgz#877d512effef2ac8be65e695f3586922e1a57d7b" @@ -11588,6 +11745,13 @@ url-loader@^4.1.1: mime-types "^2.1.27" schema-utils "^3.0.0" +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ== + dependencies: + prepend-http "^2.0.0" + url-parse@^1.5.3: version "1.5.10" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1"