From 666be863e1853691611a5815f83db1701a3390f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 15:19:02 +0000 Subject: [PATCH 1/3] Bump eslint-plugin-perfectionist from 3.9.1 to 4.0.3 Bumps [eslint-plugin-perfectionist](https://github.com/azat-io/eslint-plugin-perfectionist) from 3.9.1 to 4.0.3. - [Release notes](https://github.com/azat-io/eslint-plugin-perfectionist/releases) - [Changelog](https://github.com/azat-io/eslint-plugin-perfectionist/blob/main/changelog.md) - [Commits](https://github.com/azat-io/eslint-plugin-perfectionist/compare/v3.9.1...v4.0.3) --- updated-dependencies: - dependency-name: eslint-plugin-perfectionist dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 73 ++++++++++------------------------------------- package.json | 2 +- 2 files changed, 16 insertions(+), 59 deletions(-) diff --git a/package-lock.json b/package-lock.json index dc0908a2..9d582479 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,7 @@ "eslint": "^9.15.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-jest": "^28.9.0", - "eslint-plugin-perfectionist": "^3.9.1", + "eslint-plugin-perfectionist": "^4.0.3", "eslint-plugin-playwright": "^2.1.0", "eslint-plugin-prefer-arrow-functions": "^3.4.1", "eslint-plugin-prettier": "^5.2.1", @@ -7641,65 +7641,20 @@ } }, "node_modules/eslint-plugin-perfectionist": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-3.9.1.tgz", - "integrity": "sha512-9WRzf6XaAxF4Oi5t/3TqKP5zUjERhasHmLFHin2Yw6ZAp/EP/EVA2dr3BhQrrHWCm5SzTMZf0FcjDnBkO2xFkA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-4.0.3.tgz", + "integrity": "sha512-CyafnreF6boy4lf1XaF72U8NbkwrfjU/mOf1y6doaDMS9zGXhUU1DSk+ZPf/rVwCf1PL1m+rhHqFs+IcB8kDmA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "^8.9.0", - "@typescript-eslint/utils": "^8.9.0", - "minimatch": "^9.0.5", - "natural-compare-lite": "^1.4.0" + "@typescript-eslint/types": "^8.15.0", + "@typescript-eslint/utils": "^8.15.0", + "natural-orderby": "^5.0.0" }, "engines": { "node": "^18.0.0 || >=20.0.0" }, "peerDependencies": { - "astro-eslint-parser": "^1.0.2", - "eslint": ">=8.0.0", - "svelte": ">=3.0.0", - "svelte-eslint-parser": "^0.41.1", - "vue-eslint-parser": ">=9.0.0" - }, - "peerDependenciesMeta": { - "astro-eslint-parser": { - "optional": true - }, - "svelte": { - "optional": true - }, - "svelte-eslint-parser": { - "optional": true - }, - "vue-eslint-parser": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-perfectionist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/eslint-plugin-perfectionist/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "eslint": ">=8.0.0" } }, "node_modules/eslint-plugin-playwright": { @@ -12889,12 +12844,14 @@ "dev": true, "license": "MIT" }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "node_modules/natural-orderby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-5.0.0.tgz", + "integrity": "sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==", "dev": true, - "license": "MIT" + "engines": { + "node": ">=18" + } }, "node_modules/negotiator": { "version": "0.6.3", diff --git a/package.json b/package.json index 4bfa9b20..4b17418f 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "eslint": "^9.15.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-jest": "^28.9.0", - "eslint-plugin-perfectionist": "^3.9.1", + "eslint-plugin-perfectionist": "^4.0.3", "eslint-plugin-playwright": "^2.1.0", "eslint-plugin-prefer-arrow-functions": "^3.4.1", "eslint-plugin-prettier": "^5.2.1", From 519856590873863e1f238b3ab345be6bda5f686c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Mon, 25 Nov 2024 16:49:24 +0100 Subject: [PATCH 2/3] Not applying no-use-before-define to functions --- eslint.config.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/eslint.config.js b/eslint.config.js index b93ae7ea..99804263 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -84,7 +84,10 @@ export default tseslint.config( "error", "@typescript-eslint/no-unnecessary-qualifier": "error", "@typescript-eslint/no-unused-vars": ["error", { caughtErrors: "none" }], - "@typescript-eslint/no-use-before-define": "error", + "@typescript-eslint/no-use-before-define": [ + "error", + { functions: false }, + ], "@typescript-eslint/no-useless-empty-export": "error", "@typescript-eslint/parameter-properties": "error", "@typescript-eslint/prefer-enum-initializers": "error", From f87d92bf1ba27ca6de8146f96d856f114edb7d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Mon, 25 Nov 2024 16:49:42 +0100 Subject: [PATCH 3/3] Applied new perfectionist rules --- __tests__/test-utils/stub-endpoints.ts | 22 ++-- eslint.config.js | 2 +- src/backend/move/copyFileComments.ts | 32 +++--- src/backend/move/folderManagement.ts | 104 +++++++++--------- src/backend/move/moveFile.ts | 52 ++++----- src/backend/move/moveFolder.ts | 34 +++--- src/backend/utils/DriveBackedValue.ts | 62 +++++------ .../SafeDriveService/SafeFilesCollection.ts | 10 +- src/frontend/App.svelte | 1 - 9 files changed, 159 insertions(+), 160 deletions(-) diff --git a/__tests__/test-utils/stub-endpoints.ts b/__tests__/test-utils/stub-endpoints.ts index 3e751a9e..4ced2be0 100644 --- a/__tests__/test-utils/stub-endpoints.ts +++ b/__tests__/test-utils/stub-endpoints.ts @@ -8,23 +8,23 @@ declare global { } } -declare function _logEndpointCall( - name: string, - params: Array, -): void; +type EndpointStub = + | { delay?: number; status: "failure"; value: Error } + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- The return value of the API can be anything + | { delay?: number; status: "success"; value: any }; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any -- From google.script types +type FailureHandlerType = (error: Error, object?: any) => void; type Run = google.script.PublicEndpoints & google.script.RunnerFunctions; // eslint-disable-next-line @typescript-eslint/no-explicit-any -- From google.script types type SuccessHandlerType = (value?: any, object?: any) => void; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -- From google.script types -type FailureHandlerType = (error: Error, object?: any) => void; - -type EndpointStub = - | { delay?: number; status: "failure"; value: Error } - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- The return value of the API can be anything - | { delay?: number; status: "success"; value: any }; +declare function _logEndpointCall( + name: string, + params: Array, +): void; export async function setup( page: Page, diff --git a/eslint.config.js b/eslint.config.js index 99804263..e2402132 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,6 +1,6 @@ -import js from "@eslint/js"; import eslintComments from "@eslint-community/eslint-plugin-eslint-comments"; import commentsConfig from "@eslint-community/eslint-plugin-eslint-comments/configs"; +import js from "@eslint/js"; import jest from "eslint-plugin-jest"; import perfectionist from "eslint-plugin-perfectionist"; import playwright from "eslint-plugin-playwright"; diff --git a/src/backend/move/copyFileComments.ts b/src/backend/move/copyFileComments.ts index 7af6a6dd..e0628a39 100644 --- a/src/backend/move/copyFileComments.ts +++ b/src/backend/move/copyFileComments.ts @@ -6,22 +6,6 @@ import type { import { paginationHelper_ } from "../utils/paginationHelper"; -function listFileComments_( - fileID: string, - driveService: SafeDriveService_, -): Array { - return paginationHelper_( - (pageToken) => - driveService.Comments.list(fileID, { - fields: - "nextPageToken, items(author(isAuthenticatedUser, displayName), content, status, context, anchor, replies(author(isAuthenticatedUser, displayName), content, verb))", - maxResults: 100, - pageToken, - }), - (response) => response.items, - ); -} - export function copyFileComments_( sourceID: string, destinationID: string, @@ -46,3 +30,19 @@ export function copyFileComments_( } } } + +function listFileComments_( + fileID: string, + driveService: SafeDriveService_, +): Array { + return paginationHelper_( + (pageToken) => + driveService.Comments.list(fileID, { + fields: + "nextPageToken, items(author(isAuthenticatedUser, displayName), content, status, context, anchor, replies(author(isAuthenticatedUser, displayName), content, verb))", + maxResults: 100, + pageToken, + }), + (response) => response.items, + ); +} diff --git a/src/backend/move/folderManagement.ts b/src/backend/move/folderManagement.ts index 867dd02d..ad553def 100644 --- a/src/backend/move/folderManagement.ts +++ b/src/backend/move/folderManagement.ts @@ -13,32 +13,38 @@ export interface ListFolderContentsFields { title: true; } -function listFolderContents_( +export function deleteFolderIfEmpty_( folderID: string, - mimeTypeCondition: string, driveService: SafeDriveService_, -): Array> { - return paginationHelper_< - SafeFileList, - DeepPick - >( - (pageToken) => - driveService.Files.list( - { - capabilities: { canMoveItemOutOfDrive: true }, - id: true, - title: true, - }, - { - includeItemsFromAllDrives: true, - maxResults: 1000, - pageToken, - q: `"${folderID}" in parents and mimeType ${mimeTypeCondition} and trashed = false`, - supportsAllDrives: true, - }, - ), - (response) => response.items, +): void { + if (!isFolderEmpty_(folderID, driveService)) { + return; + } + const response = driveService.Files.get(folderID, { + userPermission: { role: true }, + }); + if ( + response.userPermission.role === "owner" || + response.userPermission.role === "organizer" + ) { + driveService.Files.remove(folderID); + } +} + +export function isFolderEmpty_( + folderID: string, + driveService: SafeDriveService_, +): boolean { + const response = driveService.Files.list( + { id: true }, + { + includeItemsFromAllDrives: true, + maxResults: 1, + q: `"${folderID}" in parents and trashed = false`, + supportsAllDrives: true, + }, ); + return response.items.length === 0; } export function listFilesInFolder_( @@ -63,36 +69,30 @@ export function listFoldersInFolder_( ); } -export function isFolderEmpty_( +function listFolderContents_( folderID: string, + mimeTypeCondition: string, driveService: SafeDriveService_, -): boolean { - const response = driveService.Files.list( - { id: true }, - { - includeItemsFromAllDrives: true, - maxResults: 1, - q: `"${folderID}" in parents and trashed = false`, - supportsAllDrives: true, - }, +): Array> { + return paginationHelper_< + SafeFileList, + DeepPick + >( + (pageToken) => + driveService.Files.list( + { + capabilities: { canMoveItemOutOfDrive: true }, + id: true, + title: true, + }, + { + includeItemsFromAllDrives: true, + maxResults: 1000, + pageToken, + q: `"${folderID}" in parents and mimeType ${mimeTypeCondition} and trashed = false`, + supportsAllDrives: true, + }, + ), + (response) => response.items, ); - return response.items.length === 0; -} - -export function deleteFolderIfEmpty_( - folderID: string, - driveService: SafeDriveService_, -): void { - if (!isFolderEmpty_(folderID, driveService)) { - return; - } - const response = driveService.Files.get(folderID, { - userPermission: { role: true }, - }); - if ( - response.userPermission.role === "owner" || - response.userPermission.role === "organizer" - ) { - driveService.Files.remove(folderID); - } } diff --git a/src/backend/move/moveFile.ts b/src/backend/move/moveFile.ts index 8e6c85dd..fe8918b2 100644 --- a/src/backend/move/moveFile.ts +++ b/src/backend/move/moveFile.ts @@ -6,17 +6,27 @@ import type { ListFolderContentsFields } from "./folderManagement"; import { copyFileComments_ } from "./copyFileComments"; -function moveFileDirectly_( - fileID: string, +export function moveFile_( + file: DeepPick, + state: MoveState_, context: MoveContext, + copyComments: boolean, driveService: SafeDriveService_, ): void { - driveService.Files.update({}, fileID, null, { - addParents: context.destinationID, - fields: "", - removeParents: context.sourceID, - supportsAllDrives: true, - }); + if (file.capabilities.canMoveItemOutOfDrive) { + try { + moveFileDirectly_(file.id, context, driveService); + return; + } catch (e) {} // eslint-disable-line no-empty -- Handled by moving by copying + } + moveFileByCopy_( + file.id, + file.title, + state, + context, + copyComments, + driveService, + ); } function moveFileByCopy_( @@ -47,25 +57,15 @@ function moveFileByCopy_( ); } -export function moveFile_( - file: DeepPick, - state: MoveState_, +function moveFileDirectly_( + fileID: string, context: MoveContext, - copyComments: boolean, driveService: SafeDriveService_, ): void { - if (file.capabilities.canMoveItemOutOfDrive) { - try { - moveFileDirectly_(file.id, context, driveService); - return; - } catch (e) {} // eslint-disable-line no-empty -- Handled by moving by copying - } - moveFileByCopy_( - file.id, - file.title, - state, - context, - copyComments, - driveService, - ); + driveService.Files.update({}, fileID, null, { + addParents: context.destinationID, + fields: "", + removeParents: context.sourceID, + supportsAllDrives: true, + }); } diff --git a/src/backend/move/moveFolder.ts b/src/backend/move/moveFolder.ts index 5e09d968..33a3cca1 100644 --- a/src/backend/move/moveFolder.ts +++ b/src/backend/move/moveFolder.ts @@ -6,23 +6,6 @@ import { listFilesInFolder_, listFoldersInFolder_ } from "./folderManagement"; import { moveFile_ } from "./moveFile"; import { resolveDestinationFolder_ } from "./resolveDestinationFolder"; -function moveFolderContentsFiles_( - state: MoveState_, - context: MoveContext, - copyComments: boolean, - driveService: SafeDriveService_, -): void { - const files = state.tryOrLog(context, () => - listFilesInFolder_(context.sourceID, driveService), - ); - if (files === null) { - return; - } - for (const file of files) { - moveFile_(file, state, context, copyComments, driveService); - } -} - export function moveFolder_( state: MoveState_, context: MoveContext, @@ -53,3 +36,20 @@ export function moveFolder_( state.removePath(context); state.saveState(); } + +function moveFolderContentsFiles_( + state: MoveState_, + context: MoveContext, + copyComments: boolean, + driveService: SafeDriveService_, +): void { + const files = state.tryOrLog(context, () => + listFilesInFolder_(context.sourceID, driveService), + ); + if (files === null) { + return; + } + for (const file of files) { + moveFile_(file, state, context, copyComments, driveService); + } +} diff --git a/src/backend/utils/DriveBackedValue.ts b/src/backend/utils/DriveBackedValue.ts index 34ca2f37..fc63cade 100644 --- a/src/backend/utils/DriveBackedValue.ts +++ b/src/backend/utils/DriveBackedValue.ts @@ -18,6 +18,37 @@ export class DriveBackedValue_ { .join(""); } + public deleteValue(): void { + const folderId = this.getExistingDriveFolderId(); + if (folderId === null) { + return; + } + const fileId = this.getExistingDriveFileId(folderId); + if (fileId !== null) { + this.deleteExistingDriveFile(fileId); + } + if (this.isExistingDriveFolderEmpty(folderId)) { + // This function works with folders as well + this.deleteExistingDriveFile(folderId); + } + } + + public loadValue(): T | null { + const folderId = this.getExistingDriveFolderId(); + if (folderId === null) { + return null; + } + const fileId = this.getExistingDriveFileId(folderId); + if (fileId === null) { + return null; + } + return this.getExistingDriveFileContents(fileId); + } + + public saveValue(value: T): void { + this.saveDriveFile(this.getDriveFolderId(), value); + } + private createDriveFolder(): string { const response = this.driveService.Files.insert( { @@ -127,35 +158,4 @@ export class DriveBackedValue_ { Utilities.newBlob(JSON.stringify(value), "application/json"), ); } - - public deleteValue(): void { - const folderId = this.getExistingDriveFolderId(); - if (folderId === null) { - return; - } - const fileId = this.getExistingDriveFileId(folderId); - if (fileId !== null) { - this.deleteExistingDriveFile(fileId); - } - if (this.isExistingDriveFolderEmpty(folderId)) { - // This function works with folders as well - this.deleteExistingDriveFile(folderId); - } - } - - public loadValue(): T | null { - const folderId = this.getExistingDriveFolderId(); - if (folderId === null) { - return null; - } - const fileId = this.getExistingDriveFileId(folderId); - if (fileId === null) { - return null; - } - return this.getExistingDriveFileContents(fileId); - } - - public saveValue(value: T): void { - this.saveDriveFile(this.getDriveFolderId(), value); - } } diff --git a/src/backend/utils/SafeDriveService/SafeFilesCollection.ts b/src/backend/utils/SafeDriveService/SafeFilesCollection.ts index ef5135ca..532d5e52 100644 --- a/src/backend/utils/SafeDriveService/SafeFilesCollection.ts +++ b/src/backend/utils/SafeDriveService/SafeFilesCollection.ts @@ -41,20 +41,20 @@ const safeFileKeys: DeepKeyof = { }, }; +export interface SafeFileList> { + items: Array>; + nextPageToken?: string | undefined; +} interface GetArg { alt?: string; } + type GetReturn, A extends GetArg> = A extends { alt: "media"; } ? string : DeepPick; -export interface SafeFileList> { - items: Array>; - nextPageToken?: string | undefined; -} - export class SafeFilesCollection_ { private readonly unsafeFiles: GoogleAppsScript.Drive.Collection.FilesCollection; diff --git a/src/frontend/App.svelte b/src/frontend/App.svelte index 97f2cd62..32ea8cc5 100644 --- a/src/frontend/App.svelte +++ b/src/frontend/App.svelte @@ -99,7 +99,6 @@ function moveErrorHandler(response: Error): void { if (response.name === "ScriptError") { - // eslint-disable-next-line @typescript-eslint/no-use-before-define -- Cyclical dependency move(); return; }