diff --git a/src/cli/cmd-add.ts b/src/cli/cmd-add.ts index 9e27e231..3c023e3b 100644 --- a/src/cli/cmd-add.ts +++ b/src/cli/cmd-add.ts @@ -13,6 +13,7 @@ import { getUserUpmConfigPathFor } from "../domain/upm-config"; import type { ReadTextFile, WriteTextFile } from "../io/fs"; import type { GetRegistryPackument } from "../io/registry"; import type { CheckUrlExists } from "../io/www"; +import { determineCwd, type ChdirOptions } from "./opt-chdir"; import { CmdOptions } from "./options"; import { parseEnvUsing } from "./parse-env"; import { ResultCodes } from "./result-codes"; @@ -20,17 +21,19 @@ import { ResultCodes } from "./result-codes"; /** * Options passed to the add command. */ -export type AddOptions = CmdOptions<{ - /** - * Whether to also add the packages to testables. - */ - test?: boolean; - /** - * Whether to run with force. This will add packages even if validation - * was not possible. - */ - force?: boolean; -}>; +export type AddOptions = CmdOptions< + ChdirOptions & { + /** + * Whether to also add the packages to testables. + */ + test?: boolean; + /** + * Whether to run with force. This will add packages even if validation + * was not possible. + */ + force?: boolean; + } +>; /** * The different command result codes for the add command. @@ -59,15 +62,17 @@ export function makeAddCmd( debugLog: DebugLog ): AddCmd { return async (pkgs, options) => { + const projectDirectory = determineCwd(process.cwd(), options); + if (!Array.isArray(pkgs)) pkgs = [pkgs]; // parse env - const env = await parseEnvUsing(log, process.env, process.cwd(), options); + const env = await parseEnvUsing(log, process.env, options); const editorVersion = await determineEditorVersionUsing( readTextFile, debugLog, - env.cwd + projectDirectory ); if (typeof editorVersion === "string") @@ -76,8 +81,6 @@ export function makeAddCmd( `${editorVersion} is unknown, the editor version check is disabled` ); - const projectDirectory = env.cwd; - const homePath = getHomePathFromEnv(process.env); const upmConfigPath = getUserUpmConfigPathFor( process.env, diff --git a/src/cli/cmd-deps.ts b/src/cli/cmd-deps.ts index a9898f10..2e397879 100644 --- a/src/cli/cmd-deps.ts +++ b/src/cli/cmd-deps.ts @@ -63,7 +63,7 @@ export function makeDepsCmd( ): DepsCmd { return async (pkg, options) => { // parse env - const env = await parseEnvUsing(log, process.env, process.cwd(), options); + const env = await parseEnvUsing(log, process.env, options); const homePath = getHomePathFromEnv(process.env); const upmConfigPath = getUserUpmConfigPathFor( diff --git a/src/cli/cmd-login.ts b/src/cli/cmd-login.ts index a185c4c7..89dd3cb6 100644 --- a/src/cli/cmd-login.ts +++ b/src/cli/cmd-login.ts @@ -78,7 +78,7 @@ export function makeLoginCmd( return async (options) => { // parse env - const env = await parseEnvUsing(log, process.env, process.cwd(), options); + const env = await parseEnvUsing(log, process.env, options); const homePath = getHomePathFromEnv(process.env); const upmConfigPath = getUserUpmConfigPathFor( diff --git a/src/cli/cmd-remove.ts b/src/cli/cmd-remove.ts index 367eadd9..1a95c748 100644 --- a/src/cli/cmd-remove.ts +++ b/src/cli/cmd-remove.ts @@ -1,11 +1,12 @@ import { Logger } from "npmlog"; import { removeDependenciesUsing } from "../app/remove-dependencies"; import { DomainName } from "../domain/domain-name"; +import { partialApply } from "../domain/fp-utils"; +import type { DebugLog } from "../domain/logging"; import { makePackageReference } from "../domain/package-reference"; import type { ReadTextFile, WriteTextFile } from "../io/fs"; -import type { DebugLog } from "../domain/logging"; -import { partialApply } from "../domain/fp-utils"; import { logError } from "./error-logging"; +import { determineCwd, type ChdirOptions } from "./opt-chdir"; import { CmdOptions } from "./options"; import { parseEnvUsing } from "./parse-env"; import { ResultCodes } from "./result-codes"; @@ -18,7 +19,7 @@ export type RemoveResultCode = ResultCodes.Ok | ResultCodes.Error; /** * Options passed to the remove command. */ -export type RemoveOptions = CmdOptions; +export type RemoveOptions = CmdOptions; /** * Cmd-handler for removing packages. @@ -47,10 +48,13 @@ export function makeRemoveCmd( ); return async (pkgs, options) => { + const projectDirectory = determineCwd(process.cwd(), options); + // parse env - const env = await parseEnvUsing(log, process.env, process.cwd(), options); + await parseEnvUsing(log, process.env, options); - const removeResult = await removeDependencies(env.cwd, pkgs).promise; + const removeResult = await removeDependencies(projectDirectory, pkgs) + .promise; if (removeResult.isErr()) { logError(log, removeResult.error); return ResultCodes.Error; diff --git a/src/cli/cmd-search.ts b/src/cli/cmd-search.ts index 44a6696d..be48fcfd 100644 --- a/src/cli/cmd-search.ts +++ b/src/cli/cmd-search.ts @@ -52,7 +52,7 @@ export function makeSearchCmd( return async (keyword, options) => { // parse env - const env = await parseEnvUsing(log, process.env, process.cwd(), options); + const env = await parseEnvUsing(log, process.env, options); const homePath = getHomePathFromEnv(process.env); const upmConfigPath = getUserUpmConfigPathFor( process.env, diff --git a/src/cli/cmd-view.ts b/src/cli/cmd-view.ts index 4455fc60..4c1dd754 100644 --- a/src/cli/cmd-view.ts +++ b/src/cli/cmd-view.ts @@ -50,7 +50,7 @@ export function makeViewCmd( ): ViewCmd { return async (pkg, options) => { // parse env - const env = await parseEnvUsing(log, process.env, process.cwd(), options); + const env = await parseEnvUsing(log, process.env, options); const homePath = getHomePathFromEnv(process.env); const upmConfigPath = getUserUpmConfigPathFor( process.env, diff --git a/src/cli/index.ts b/src/cli/index.ts index 5b08f45b..e4e0ede8 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -22,6 +22,7 @@ import { makeRemoveCmd } from "./cmd-remove"; import { makeSearchCmd } from "./cmd-search"; import { makeViewCmd } from "./cmd-view"; import { withErrorLogger } from "./error-logging"; +import { chdirOption } from "./opt-chdir"; import { CmdOptions } from "./options"; import { mustBeDomainName, @@ -109,7 +110,6 @@ notifier.notify(); const program = createCommand() .version(module.exports.version) - .option("-c, --chdir ", "change the working directory") .option("-r, --registry ", "specify registry url", mustBeRegistryUrl) .option("-v, --verbose", "output extra debugging") .option("--system-user", "auth for Windows system user") @@ -140,6 +140,7 @@ program eachValue(mustBePackageReference) ) .aliases(["install", "i"]) + .addOption(chdirOption) .option("-t, --test", "add package as testable") .option( "-f, --force", @@ -168,6 +169,7 @@ program ) .aliases(["rm", "uninstall"]) .description("remove package from manifest json") + .addOption(chdirOption) .action( withErrorLogger( log, diff --git a/src/cli/opt-chdir.ts b/src/cli/opt-chdir.ts new file mode 100644 index 00000000..abe23946 --- /dev/null +++ b/src/cli/opt-chdir.ts @@ -0,0 +1,35 @@ +import { Option } from "@commander-js/extra-typings"; +import path from "path"; + +/** + * The `chdir` cli-option for allowing users to switch their working + * directory. + */ +export const chdirOption = new Option( + "-c, --chdir ", + "change the working directory" +) + .default(null) + .makeOptionMandatory(true); + +/** + * Parsed cli options which include a changed working directory. + */ +export type ChdirOptions = { + /** + * Overriden working-directory. + */ + chdir: string | null; +}; + +/** + * Determines the directory in which to execute commands. + * @param processCwd The process cwd. + * @param options Cmd options. + */ +export function determineCwd( + processCwd: string, + options: ChdirOptions +): string { + return options.chdir !== null ? path.resolve(options.chdir) : processCwd; +} diff --git a/src/cli/options.ts b/src/cli/options.ts index 0a23834c..d0669471 100644 --- a/src/cli/options.ts +++ b/src/cli/options.ts @@ -1,3 +1,5 @@ +import type { OptionValues } from "@commander-js/extra-typings"; + /** * Options which are shared between commands. */ @@ -26,15 +28,11 @@ type GlobalOptions = Readonly<{ * Whether to authenticate as a Windows system-user. */ systemUser?: boolean; - /** - * Override working directory. - */ - chdir?: string; }>; /** * Command-options. Extends the given record with {@link GlobalOptions}. */ -export type CmdOptions< - TOptions extends Record = Record -> = Readonly; +export type CmdOptions = Readonly< + TOptions & GlobalOptions +>; diff --git a/src/cli/parse-env.ts b/src/cli/parse-env.ts index 6eb82a79..2006dabb 100644 --- a/src/cli/parse-env.ts +++ b/src/cli/parse-env.ts @@ -1,6 +1,5 @@ import chalk from "chalk"; import { Logger } from "npmlog"; -import path from "path"; import { CustomError } from "ts-custom-error"; import { coerceRegistryUrl, @@ -20,10 +19,6 @@ export class RegistryAuthLoadError extends CustomError { * Contains information about the environment and context a command is run in. */ export type Env = Readonly<{ - /** - * The working directory. - */ - cwd: string; /** * Whether the user is a system-user. */ @@ -38,15 +33,6 @@ export type Env = Readonly<{ primaryRegistryUrl: RegistryUrl; }>; -/** - * Determines the directory in which to execute commands. - * @param processCwd The process cwd. - * @param options Cmd options. - */ -export function determineCwd(processCwd: string, options: CmdOptions): string { - return options.chdir !== undefined ? path.resolve(options.chdir) : processCwd; -} - /** * Determines which log level to use for output. * @param options Cmd options. @@ -97,14 +83,12 @@ export function determinePrimaryRegistryUrl(options: CmdOptions): RegistryUrl { * command-options for further usage. * @param log The logger that is used in the application. * @param envVars Environment variables. - * @param processCwd The process directory. * @param options The options passed to the current command. * @returns Environment information. */ export async function parseEnvUsing( log: Logger, envVars: Record, - processCwd: string, options: CmdOptions ): Promise { // log level @@ -126,11 +110,7 @@ export async function parseEnvUsing( // registries const primaryRegistryUrl = determinePrimaryRegistryUrl(options); - // cwd - const cwd = determineCwd(processCwd, options); - return { - cwd, primaryRegistryUrl, systemUser, upstream, diff --git a/test/unit/cli/opt-chdir.test.ts b/test/unit/cli/opt-chdir.test.ts new file mode 100644 index 00000000..f78e0947 --- /dev/null +++ b/test/unit/cli/opt-chdir.test.ts @@ -0,0 +1,22 @@ +import path from "path"; +import { determineCwd } from "../../../src/cli/opt-chdir"; + +describe("chdir option", () => { + const testRootPath = "/users/some-user/projects/MyUnityProject"; + + it("should be process directory by default", () => { + const actual = determineCwd(testRootPath, { chdir: null }); + + expect(actual).toEqual(testRootPath); + }); + + it("should be specified path if overridden", () => { + const expected = path.resolve("/some/other/path"); + + const actual = determineCwd(testRootPath, { + chdir: expected, + }); + + expect(actual).toEqual(expected); + }); +}); diff --git a/test/unit/cli/parse-env.test.ts b/test/unit/cli/parse-env.test.ts index e7db725a..ffa49de0 100644 --- a/test/unit/cli/parse-env.test.ts +++ b/test/unit/cli/parse-env.test.ts @@ -1,6 +1,4 @@ -import path from "path"; import { - determineCwd, determineIsSystemUser, determineLogLevel, determinePrimaryRegistryUrl, @@ -10,7 +8,6 @@ import { import { openupmRegistryUrl } from "../../../src/domain/registry-url"; import { someRegistryUrl } from "../../common/data-registry"; -const testRootPath = "/users/some-user/projects/MyUnityProject"; describe("parse env", () => { describe("log-level", () => { @@ -130,22 +127,4 @@ describe("parse env", () => { expect(actual).toEqual(someRegistryUrl); }); }); - - describe("cwd", () => { - it("should be process directory by default", () => { - const actual = determineCwd(testRootPath, {}); - - expect(actual).toEqual(testRootPath); - }); - - it("should be specified path if overridden", () => { - const expected = path.resolve("/some/other/path"); - - const actual = determineCwd(testRootPath, { - chdir: expected, - }); - - expect(actual).toEqual(expected); - }); - }); });