Skip to content

Commit 7156355

Browse files
davidmurdochsam
authored and
sam
committed
feat: handle mutually exclusive args in cli (trufflesuite#732)
1 parent 223f974 commit 7156355

File tree

5 files changed

+55
-16
lines changed

5 files changed

+55
-16
lines changed

src/chains/ethereum/options/src/database-options.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,15 @@ export const DatabaseOptions: Definitions<DatabaseConfig> = {
3838
normalize,
3939
cliDescription: "Specify an alternative database instance, like MemDOWN",
4040
disableInCLI: true,
41-
legacyName: "db"
41+
legacyName: "db",
42+
conflicts: ["dbPath"]
4243
},
4344
dbPath: {
4445
normalize,
4546
cliDescription: "Specify a path to a directory to save the chain database.",
4647
legacyName: "db_path",
4748
cliAliases: ["db", "db_path"],
48-
cliType: "string"
49+
cliType: "string",
50+
conflicts: ["db"]
4951
}
5052
};

src/chains/ethereum/options/src/wallet-options.ts

+10-5
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,8 @@ export const WalletOptions: Definitions<WalletConfig> = {
200200
default: () => 10,
201201
legacyName: "total_accounts",
202202
cliAliases: ["a", "accounts"],
203-
cliType: "number"
203+
cliType: "number",
204+
conflicts: ["accounts"]
204205
},
205206
accounts: {
206207
normalize,
@@ -217,14 +218,16 @@ export const WalletOptions: Definitions<WalletConfig> = {
217218
balance: BigInt(balance)
218219
} as OptionsAccount;
219220
});
220-
}
221+
},
222+
conflicts: ["totalAccounts"]
221223
},
222224
deterministic: {
223225
normalize,
224226
cliDescription: "Use pre-defined, deterministic seed.",
225227
default: () => false,
226228
cliAliases: ["d", "deterministic"],
227-
cliType: "boolean"
229+
cliType: "boolean",
230+
conflicts: ["mnemonic", "seed"]
228231
},
229232
seed: {
230233
normalize,
@@ -240,7 +243,8 @@ export const WalletOptions: Definitions<WalletConfig> = {
240243
"Random value, unless wallet.deterministic is specified",
241244
legacyName: "seed",
242245
cliAliases: ["s", "seed"],
243-
cliType: "string"
246+
cliType: "string",
247+
conflicts: ["mnemonic", "deterministic"]
244248
},
245249
mnemonic: {
246250
normalize,
@@ -254,7 +258,8 @@ export const WalletOptions: Definitions<WalletConfig> = {
254258
defaultDescription: "Generated from wallet.seed",
255259
legacyName: "mnemonic",
256260
cliAliases: ["m", "mnemonic"],
257-
cliType: "string"
261+
cliType: "string",
262+
conflicts: ["seed", "deterministic"]
258263
},
259264
unlockedAccounts: {
260265
normalize,

src/packages/cli/src/args.ts

+6
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ function processOption(
9393
coerce: optionObj.cliCoerce
9494
};
9595

96+
if ("conflicts" in optionObj) {
97+
options.conflicts = (optionObj as {
98+
conflicts: string[];
99+
}).conflicts.map(c => `${category}.${c}`);
100+
}
101+
96102
const key = `${category}.${option}`;
97103

98104
// First, create *hidden* deprecated aliases...

src/packages/options/src/definition.ts

+21-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { Base, CliTypeMap, CliTypes } from "./base";
2-
import { ExclusiveGroupUnionAndUnconstrainedPlus } from "./exclusive";
2+
import {
3+
ExclusiveGroupsByName,
4+
ExclusiveGroupUnionAndUnconstrainedPlus
5+
} from "./exclusive";
36
import {
47
Legacy,
58
OptionCliType,
@@ -33,22 +36,31 @@ export type Definitions<C extends Base.Config> = {
3336
readonly disableInCLI?: boolean;
3437
readonly cliAliases?: string[];
3538
readonly cliChoices?: string[] | number[];
36-
} & (void extends OptionHasCliType<C, N>
37-
? {
38-
readonly cliType?: CliTypeMap<CliTypes> | null;
39-
}
39+
// exclusiveGroups (conflicts)
40+
} & (C[ExclusiveGroupsByName<C, N>] extends never
41+
? {}
4042
: {
41-
readonly cliType?: CliTypeMap<OptionCliType<C, N>> | null;
42-
readonly cliCoerce?: (
43-
cliType: OptionCliType<C, N>
44-
) => OptionRawType<C, N>;
43+
readonly conflicts: ExclusiveGroupsByName<C, N>[];
4544
}) &
45+
// cliType
46+
(void extends OptionHasCliType<C, N>
47+
? {
48+
readonly cliType?: CliTypeMap<CliTypes> | null;
49+
}
50+
: {
51+
readonly cliType?: CliTypeMap<OptionCliType<C, N>> | null;
52+
readonly cliCoerce?: (
53+
cliType: OptionCliType<C, N>
54+
) => OptionRawType<C, N>;
55+
}) &
56+
// hasDefault
4657
(void extends OptionHasDefault<C, N>
4758
? {}
4859
: {
4960
readonly default: (config: InternalConfig<C>) => OptionType<C, N>;
5061
readonly defaultDescription?: string;
5162
}) &
63+
// hasLegacy
5264
(void extends OptionHasLegacy<C, N>
5365
? {}
5466
: {

src/packages/options/src/exclusive.ts

+14
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,20 @@ type Combine<
9595
? I
9696
: never;
9797

98+
export type ExclusiveGroupsByName<
99+
C extends Base.Config,
100+
N extends OptionName<C>,
101+
GRPS extends ExclusiveGroups<C> = ExclusiveGroups<C>
102+
> = GRPS extends [infer GRP, ...infer Rest]
103+
? GRP extends unknown[]
104+
? N extends DeepTupleToUnion<GRP>
105+
? Exclude<DeepTupleToUnion<GRP>, N>
106+
: Rest extends any[]
107+
? ExclusiveGroupsByName<C, N, Rest>
108+
: never
109+
: never
110+
: never;
111+
98112
type IsNeverType<T> = [T] extends [never] ? true : never;
99113
export type ExclusiveGroupUnionAndUnconstrainedPlus<
100114
C extends Base.Config,

0 commit comments

Comments
 (0)