scriptable-testlab
Version:
A lightweight, efficient tool designed to manage and update scripts for Scriptable.
107 lines (92 loc) • 2.81 kB
text/typescript
import path from 'path';
import {ERROR_MESSAGES, FileManagerError} from '../types/errors';
import {FileSystemNode} from '../types/file';
/**
* Validates if a file path is valid and within the root directory
*/
export function validatePath(filePath: string, rootPath: string): void {
if (!filePath || typeof filePath !== 'string') {
throw new FileManagerError(ERROR_MESSAGES.INVALID_PATH, 'INVALID_PATH', filePath);
}
const normalizedPath = path.normalize(filePath).replace(/\\/g, '/');
const normalizedRoot = path.normalize(rootPath).replace(/\\/g, '/');
if (!normalizedPath.startsWith(normalizedRoot)) {
throw new FileManagerError(ERROR_MESSAGES.OUTSIDE_ROOT, 'INVALID_PATH', filePath);
}
}
/**
* Validates if a node exists and is of the expected type
*/
export function validateNode(
node: FileSystemNode | undefined,
expectedType: 'file' | 'directory',
path: string,
): asserts node is FileSystemNode {
if (!node) {
throw new FileManagerError(
expectedType === 'file' ? ERROR_MESSAGES.FILE_NOT_FOUND : ERROR_MESSAGES.DIRECTORY_NOT_FOUND,
'NOT_FOUND',
path,
);
}
if (node.type !== expectedType) {
throw new FileManagerError(
expectedType === 'file' ? ERROR_MESSAGES.NOT_A_FILE : ERROR_MESSAGES.NOT_A_DIRECTORY,
'INVALID_PATH',
path,
);
}
}
/**
* Creates a deep clone of a file system node
*/
export function cloneNode(node: FileSystemNode): FileSystemNode {
const clonedMetadata = {
...node.metadata,
creationDate: new Date(node.metadata.creationDate),
modificationDate: new Date(node.metadata.modificationDate),
tags: node.metadata.tags ? new Set(node.metadata.tags) : undefined,
extendedAttributes: node.metadata.extendedAttributes ? new Map(node.metadata.extendedAttributes) : undefined,
};
if (node.type === 'file') {
return {
type: 'file',
content: node.content,
metadata: clonedMetadata,
};
}
return {
type: 'directory',
children: new Map(node.children),
metadata: clonedMetadata,
};
}
/**
* Calculates the total size of a directory
*/
export function calculateDirectorySize(dir: FileSystemNode): number {
if (dir.type !== 'directory') {
return 0;
}
let totalSize = 0;
for (const child of dir.children?.values() ?? []) {
if (child.type === 'file') {
totalSize += child.metadata.size;
} else {
totalSize += calculateDirectorySize(child);
}
}
return totalSize;
}
export type FileSystemUtils = {
validatePath: typeof validatePath;
validateNode: typeof validateNode;
cloneNode: typeof cloneNode;
calculateDirectorySize: typeof calculateDirectorySize;
};
export const FileSystemUtils: FileSystemUtils = {
validatePath,
validateNode,
cloneNode,
calculateDirectorySize,
};