diff --git a/__tests__/dav/davPermissions.spec.ts b/__tests__/dav/davPermissions.spec.ts index dcae25d65..a48be6e5e 100644 --- a/__tests__/dav/davPermissions.spec.ts +++ b/__tests__/dav/davPermissions.spec.ts @@ -11,19 +11,19 @@ const dataSet = [ { input: undefined, permissions: Permission.NONE }, { input: null, permissions: Permission.NONE }, { input: '-', permissions: Permission.NONE }, - { input: 'C', permissions: Permission.CREATE }, - { input: 'K', permissions: Permission.CREATE }, + { input: 'CK', permissions: Permission.CREATE }, { input: 'G', permissions: Permission.READ }, - { input: 'W', permissions: Permission.UPDATE }, - { input: 'N', permissions: Permission.UPDATE }, - { input: 'V', permissions: Permission.UPDATE }, + { input: 'W', permissions: Permission.WRITE }, + { input: 'NV', permissions: Permission.UPDATE }, { input: 'D', permissions: Permission.DELETE }, { input: 'R', permissions: Permission.SHARE }, - { input: 'CKGW', permissions: Permission.CREATE | Permission.READ | Permission.UPDATE }, + { input: 'GCK', permissions: Permission.READ | Permission.CREATE }, + { input: 'GNV', permissions: Permission.READ | Permission.UPDATE }, + { input: 'GNVCK', permissions: Permission.READ | Permission.CREATE | Permission.UPDATE }, { input: 'GR', permissions: Permission.READ | Permission.SHARE }, { input: 'GD', permissions: Permission.READ | Permission.DELETE }, - { input: 'RGDNVW', permissions: Permission.UPDATE | Permission.READ | Permission.DELETE | Permission.SHARE }, - { input: 'RGDNVCK', permissions: Permission.UPDATE | Permission.READ | Permission.DELETE | Permission.CREATE | Permission.SHARE }, + { input: 'RGDNVW', permissions: Permission.READ | Permission.UPDATE | Permission.WRITE | Permission.DELETE | Permission.SHARE }, + { input: 'RGDNVCK', permissions: Permission.READ | Permission.UPDATE | Permission.CREATE | Permission.DELETE | Permission.SHARE }, ] describe('davParsePermissions', () => { diff --git a/lib/actions/fileAction.ts b/lib/actions/fileAction.ts index 5e85169e6..b2704f1bf 100644 --- a/lib/actions/fileAction.ts +++ b/lib/actions/fileAction.ts @@ -6,10 +6,12 @@ import type { ActionContext, ActionContextSingle } from '../types.ts' import logger from '../utils/logger.ts' -export enum DefaultType { - DEFAULT = 'default', - HIDDEN = 'hidden', -} +export const DefaultType = Object.freeze({ + DEFAULT: 'default', + HIDDEN: 'hidden', +}) + +export type TDefaultType = typeof DefaultType[keyof typeof DefaultType] export interface IHotkeyConfig { /** @@ -91,14 +93,17 @@ export interface FileActionData { /** * Make this action the default. - * If multiple actions are default, the first one - * will be used. The other ones will be put as first - * entries in the actions menu iff DefaultType.Hidden is not used. - * A DefaultType.Hidden action will never be shown + * + * If multiple actions are default, the first one will be used. + * The other ones will be put as first entries in the actions menu iff `DefaultType.Hidden` is not used. + * + * A `DefaultType.Hidden` action will never be shown * in the actions menu even if another action takes * its place as default. + * + * @see DefaultType */ - default?: DefaultType, + default?: TDefaultType, /** * If true, the renderInline function will be called */ diff --git a/lib/dav/davPermissions.ts b/lib/dav/davPermissions.ts index 01f0b350e..a8ee95bb4 100644 --- a/lib/dav/davPermissions.ts +++ b/lib/dav/davPermissions.ts @@ -1,28 +1,39 @@ -/** +/*! * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ + import { Permission } from '../permissions' /** * Parse the WebDAV permission string to a permission enum * - * @param permString The DAV permission string + * @param permString - The DAV permission string */ -export const parsePermissions = function(permString = ''): number { +export function parsePermissions(permString = ''): number { let permissions = Permission.NONE - - if (!permString) { return permissions } - - if (permString.includes('C') || permString.includes('K')) { permissions |= Permission.CREATE } - - if (permString.includes('G')) { permissions |= Permission.READ } - - if (permString.includes('W') || permString.includes('N') || permString.includes('V')) { permissions |= Permission.UPDATE } - - if (permString.includes('D')) { permissions |= Permission.DELETE } - - if (permString.includes('R')) { permissions |= Permission.SHARE } + if (!permString) { + return permissions + } + + if (permString.includes('G')) { + permissions |= Permission.READ + } + if (permString.includes('W')) { + permissions |= Permission.WRITE + } + if (permString.includes('CK')) { + permissions |= Permission.CREATE + } + if (permString.includes('NV')) { + permissions |= Permission.UPDATE + } + if (permString.includes('D')) { + permissions |= Permission.DELETE + } + if (permString.includes('R')) { + permissions |= Permission.SHARE + } return permissions } diff --git a/lib/newMenu/NewMenu.ts b/lib/newMenu/NewMenu.ts index 0495075cc..f3de6d5e2 100644 --- a/lib/newMenu/NewMenu.ts +++ b/lib/newMenu/NewMenu.ts @@ -7,22 +7,24 @@ import type { IFolder, INode } from '../node/index.ts' import logger from '../utils/logger.ts' -export enum NewMenuEntryCategory { +export const NewMenuEntryCategory = Object.freeze({ /** * For actions where the user is intended to upload from their device */ - UploadFromDevice = 0, + UploadFromDevice: 0, /** * For actions that create new nodes on the server without uploading */ - CreateNew = 1, + CreateNew: 1, /** * For everything not matching the other categories */ - Other = 2, -} + Other: 2, +}) + +export type TNewMenuEntryCategory = typeof NewMenuEntryCategory[keyof typeof NewMenuEntryCategory] export interface NewMenuEntry { /** Unique ID */ @@ -31,10 +33,12 @@ export interface NewMenuEntry { /** * Category to put this entry in * (supported since Nextcloud 30) - * @since 3.3.0 + * * @default NewMenuEntryCategory.CreateNew + * @see NewMenuEntryCategory + * @since 3.3.0 */ - category?: NewMenuEntryCategory + category?: TNewMenuEntryCategory /** Translatable string displayed in the menu */ displayName: string diff --git a/lib/node/file.ts b/lib/node/file.ts index 640ef6760..bca295d05 100644 --- a/lib/node/file.ts +++ b/lib/node/file.ts @@ -2,6 +2,7 @@ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ + import type { NodeConstructorData } from './node' import { FileType } from './fileType' @@ -13,7 +14,7 @@ export class File extends Node { super(data, davService) } - get type(): FileType.File { + get type(): typeof FileType.File { return FileType.File } diff --git a/lib/node/fileType.ts b/lib/node/fileType.ts index c33d99b61..e53580544 100644 --- a/lib/node/fileType.ts +++ b/lib/node/fileType.ts @@ -3,7 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -export enum FileType { - Folder = 'folder', - File = 'file', -} +export const FileType = Object.freeze({ + Folder: 'folder', + File: 'file', +}) + +export type TFileType = typeof FileType[keyof typeof FileType] diff --git a/lib/node/folder.ts b/lib/node/folder.ts index 296327cd3..f04a765ac 100644 --- a/lib/node/folder.ts +++ b/lib/node/folder.ts @@ -2,6 +2,7 @@ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ + import type { NodeConstructorData } from './node' import { FileType } from './fileType' @@ -17,7 +18,7 @@ export class Folder extends Node { }, davService) } - get type(): FileType.Folder { + get type(): typeof FileType.Folder { return FileType.Folder } diff --git a/lib/node/node.ts b/lib/node/node.ts index 8c4bb268d..dbc2cc65a 100644 --- a/lib/node/node.ts +++ b/lib/node/node.ts @@ -3,21 +3,24 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ +import type { TFileType } from './fileType.ts' + import { basename, dirname, encodePath, extname } from '@nextcloud/paths' import { Permission } from '../permissions' -import { FileType } from './fileType' import { Attribute, fixDates, fixRegExp, isDavResource, NodeData, validateData } from './nodeData' -export enum NodeStatus { +export const NodeStatus = Object.freeze({ /** This is a new node and it doesn't exists on the filesystem yet */ - NEW = 'new', + NEW: 'new', /** This node has failed and is unavailable */ - FAILED = 'failed', + FAILED: 'failed', /** This node is currently loading or have an operation in progress */ - LOADING = 'loading', + LOADING: 'loading', /** This node is locked and cannot be modified */ - LOCKED = 'locked', -} + LOCKED: 'locked', +}) + +export type TNodeStatus = typeof NodeStatus[keyof typeof NodeStatus] export type NodeConstructorData = [NodeData, RegExp?] @@ -147,7 +150,7 @@ export abstract class Node { /** * Is it a file or a folder ? */ - abstract get type(): FileType + abstract get type(): TFileType /** * Get the file mime @@ -217,7 +220,7 @@ export abstract class Node { /** * Get the file permissions */ - get permissions(): Permission { + get permissions(): number { // If this is not a dav resource, we can only read it if (this.owner === null && !this.isDavResource) { return Permission.READ @@ -232,7 +235,7 @@ export abstract class Node { /** * Set the file permissions */ - set permissions(permissions: Permission) { + set permissions(permissions: number) { validateData({ ...this._data, permissions }, this._knownDavService) this.updateMtime() this._data.permissions = permissions @@ -307,14 +310,14 @@ export abstract class Node { /** * Get the node status. */ - get status(): NodeStatus|undefined { + get status(): TNodeStatus|undefined { return this._data?.status } /** * Set the node status. */ - set status(status: NodeStatus|undefined) { + set status(status: TNodeStatus|undefined) { validateData({ ...this._data, status }, this._knownDavService) this._data.status = status } diff --git a/lib/node/nodeData.ts b/lib/node/nodeData.ts index 757cef151..8b0792e67 100644 --- a/lib/node/nodeData.ts +++ b/lib/node/nodeData.ts @@ -6,7 +6,7 @@ import { join } from '@nextcloud/paths' import { Permission } from '../permissions' -import { NodeStatus } from './node' +import { NodeStatus, TNodeStatus } from './node' // eslint-disable-next-line @typescript-eslint/no-explicit-any export interface Attribute { [key: string]: any } @@ -41,8 +41,13 @@ export interface NodeData { /** The node size type */ size?: number - /** The node permissions */ - permissions?: Permission + /** + * The node permissions. + * + * A binary mask of `Permission` values. + * @see Permission + */ + permissions?: number /** The owner UID of this node */ owner: string|null @@ -54,7 +59,7 @@ export interface NodeData { attributes?: Attribute /** The node status */ - status?: NodeStatus + status?: TNodeStatus } /** diff --git a/lib/permissions.ts b/lib/permissions.ts index 0bf015db3..c95a66eba 100644 --- a/lib/permissions.ts +++ b/lib/permissions.ts @@ -6,12 +6,37 @@ /** * Node permissions */ -export enum Permission { - NONE = 0, - CREATE = 4, - READ = 1, - UPDATE = 2, - DELETE = 8, - SHARE = 16, - ALL = 31, -} +export const Permission = Object.freeze({ + /** + * No permissions granted + */ + NONE: 0, + /** + * Can read the file content + */ + READ: 1, + /** + * Can modify the file itself (move, rename, etc) + */ + UPDATE: 2, + /** + * Can create new files/folders inside a folder + */ + CREATE: 4, + /** + * Can change the file content + */ + WRITE: 4, + /** + * Can delete the node + */ + DELETE: 8, + /** + * Can share the node + */ + SHARE: 16, + /** + * All permissions are granted + */ + ALL: 31, +}) diff --git a/lib/utils/fileSorting.ts b/lib/utils/fileSorting.ts index 7f688788d..91bcb566d 100644 --- a/lib/utils/fileSorting.ts +++ b/lib/utils/fileSorting.ts @@ -9,18 +9,20 @@ import type { SortingOrder } from './sorting.ts' import { FileType } from '../node/fileType.ts' import { orderBy } from './sorting.ts' -export enum FilesSortingMode { - Name = 'basename', - Modified = 'mtime', - Size = 'size', -} +export const FilesSortingMode = Object.freeze({ + Name: 'basename', + Modified: 'mtime', + Size: 'size', +}) + +export type TFilesSortingMode = typeof FilesSortingMode[keyof typeof FilesSortingMode] export interface FilesSortingOptions { /** * They key to order the files by * @default FilesSortingMode.Name */ - sortingMode?: FilesSortingMode | string + sortingMode?: TFilesSortingMode | string /** * @default 'asc' diff --git a/lib/utils/filename-validation.ts b/lib/utils/filename-validation.ts index 17b7a8121..b18554ab4 100644 --- a/lib/utils/filename-validation.ts +++ b/lib/utils/filename-validation.ts @@ -16,11 +16,13 @@ interface NextcloudCapabilities extends Record { } } -export enum InvalidFilenameErrorReason { - ReservedName = 'reserved name', - Character = 'character', - Extension = 'extension', -} +export const InvalidFilenameErrorReason = Object.freeze({ + ReservedName: 'reserved name', + Character: 'character', + Extension: 'extension', +}) + +export type TInvalidFilenameErrorReason = typeof InvalidFilenameErrorReason[keyof typeof InvalidFilenameErrorReason] interface InvalidFilenameErrorOptions { /** @@ -31,7 +33,7 @@ interface InvalidFilenameErrorOptions { /** * Reason why the validation failed */ - reason: InvalidFilenameErrorReason + reason: TInvalidFilenameErrorReason /** * Part of the filename that caused this error diff --git a/tsconfig.json b/tsconfig.json index 812e2e265..9032b449d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "allowSyntheticDefaultImports": true, "allowImportingTsExtensions": true, + "erasableSyntaxOnly": true, "moduleResolution": "Bundler", "target": "ESNext", "module": "ESNext",