import { Assert, text } from '@rsdk/common'; import { accessSync, existsSync, lstatSync } from 'node:fs'; import path from 'node:path'; import { cwd } from 'node:process'; import type { PropertyParser } from '../../types'; export class FsPathParser implements PropertyParser { constructor(private readonly objectType: 'file' | 'dir') {} type(): string { return 'string(fs_path)'; } description(): string { return text` Extracts path to file or directory. Checks that object exists on file system and that application has access to it. `; } parse(value: unknown): string { Assert.isString(value); const wasRelative = !path.isAbsolute(value); const absolutePath = wasRelative ? path.join(cwd(), value) : value; if (!existsSync(absolutePath)) { const warning = wasRelative ? ' Since you have used relative path, check you current working directory is repos root.' : ''; throw new Error( `File or directory <${absolutePath}> not found!${warning}`, ); } try { accessSync(absolutePath); } catch { throw new Error(`Can't access <${absolutePath}>!`); } const stat = lstatSync(absolutePath); /** * Otherwise we'll have problems with IsNotDirectoryException * when using symlinks. */ if (stat.isSymbolicLink()) { return absolutePath; } if (this.objectType === 'dir' && !stat.isDirectory()) { throw new Error(`<${absolutePath}> is not a directory!`); } if (this.objectType === 'file' && !stat.isFile()) { throw new Error(`<${absolutePath}> is not a file!`); } return absolutePath; } }