resolveSelection function
Resolve positionals + namespace + locale into a KeySelection
against project. Throws SelectionFailure with a ready-to-print message
when the request cannot be honoured.
Every positional is a key. Locale selection is --locale, because a
variadic subject cannot also carry an optional trailing locale without
guessing which one a bare vi is meant to be. Callers that pass a locale
name positionally get told exactly that rather than "no such key".
Implementation
KeySelection resolveSelection({
required DialectProject project,
required String command,
required List<String> positionals,
String? namespace,
String? locale,
}) {
final targets = project.translations.keys.toList();
if (locale != null && !project.translations.containsKey(locale)) {
throw SelectionFailure(64, [
'Locale `$locale` is not a configured target locale. '
'Targets: ${targets.join(', ')}.',
]);
}
final selected = <String>{};
if (namespace != null) {
final inNamespace = [
for (final e in project.source.entries)
if (e.metadata?.namespace == namespace) e.key,
];
if (inNamespace.isEmpty) {
final known = {
for (final e in project.source.entries)
if (e.metadata?.namespace != null) e.metadata!.namespace!,
}.toList()..sort();
throw SelectionFailure(65, [
'No source key declares `namespace: $namespace`.',
known.isEmpty
? ' This source has no namespaced keys yet.'
: ' Namespaces in this source: ${known.join(', ')}.',
]);
}
selected.addAll(inNamespace);
}
final unknown = <String>[];
for (final key in positionals) {
if (project.source.entryFor(key) == null) {
unknown.add(key);
} else {
selected.add(key);
}
}
if (unknown.isNotEmpty) {
final lines = <String>[
unknown.length == 1
? 'Key `${unknown.first}` is not in the source ARB — nothing to '
'$command against. Add it to dialect/source first.'
: '${unknown.length} keys are not in the source ARB: '
'${unknown.join(', ')}. Add them to dialect/source first.',
];
// The one migration everybody will hit: `dialect lock brand vi` used to
// mean "vi only", and now reads as a second key.
final asLocale = unknown.where(targets.contains).toList();
if (asLocale.isNotEmpty) {
lines.add(
' `${asLocale.first}` is a locale, not a key — $command takes any '
'number of keys now, so locale selection moved to '
'`--locale ${asLocale.first}`.',
);
}
throw SelectionFailure(65, lines);
}
if (selected.isEmpty) {
throw SelectionFailure(64, [
'$command takes one or more <key>s, or --namespace <name>.',
' e.g. dialect $command brandTagline',
' dialect $command webAboutTitle webAboutBody --locale vi',
' dialect $command --namespace web',
]);
}
return KeySelection(
keys: selected.toList()..sort(),
locales: locale != null ? [locale] : targets,
);
}