diff --git a/src/infrastructure/application/cli/program.ts b/src/infrastructure/application/cli/program.ts index 7729a80a..74439e68 100644 --- a/src/infrastructure/application/cli/program.ts +++ b/src/infrastructure/application/cli/program.ts @@ -1,6 +1,6 @@ import {Argument, Command, InvalidOptionArgumentError, Option} from '@commander-js/extra-typings'; import type {JsonPrimitive, JsonValue} from '@croct/json'; -import {realpathSync} from 'fs'; +import {realpathSync, statSync} from 'fs'; import {ApiKey} from '@croct/sdk/apiKey'; import {Token} from '@croct/sdk/token'; import {Cli} from '@/infrastructure/application/cli/cli'; @@ -21,11 +21,34 @@ function createProgram(config: Configuration): typeof program { .description('Manage your Croct projects') .enablePositionalOptions() .option('--cwd ', 'The working directory.', path => { + let directory: string; + let isDirectory: boolean; + try { - return realpathSync(path); - } catch { - throw new InvalidOptionArgumentError('The path does not exist.'); + directory = realpathSync(path); + isDirectory = statSync(directory).isDirectory(); + } catch (error) { + const code = error instanceof Error && 'code' in error ? error.code : null; + + switch (code) { + case 'ENOENT': + case 'ENOTDIR': + throw new InvalidOptionArgumentError('The path does not exist.'); + + case 'EACCES': + case 'EPERM': + throw new InvalidOptionArgumentError('The path is not accessible.'); + + default: + throw new InvalidOptionArgumentError('The path cannot be resolved.'); + } } + + if (!isDirectory) { + throw new InvalidOptionArgumentError('The path is not a directory.'); + } + + return directory; }) .addOption( new Option('--api-key ', 'The API key to use for authentication.') @@ -457,6 +480,9 @@ export async function run(args: string[] = process.argv, welcome = true): Promis ? undefined : new URL(options.registry), configurationFile: options.config, + directories: { + current: options.cwd, + }, }); const template = getTemplate(invocation.args);