Args.parse constructor
Implementation
factory Args.parse(List<String> args) {
// --no-<key> should be false under <key>
// --<key> should be true under <key>
// --key=value should be value under key
final mapped = <String, dynamic>{};
final rest = <String>[];
final path = <String>[];
final abbr = <String, dynamic>{};
final original = [...args];
void add(String rawKey, dynamic rawValue) {
final key = switch (rawKey.split('--')) {
[final key] => key,
[_, final key] => key,
_ => throw ArgumentError('Invalid key: $rawKey'),
};
var value = switch (rawValue) {
final String string
when string.contains(RegExp(r'^".*"$')) ||
string.contains(RegExp(r"^'.*'$")) =>
string.substring(1, string.length - 1),
final value => value,
};
if (int.tryParse('$value') case final int v) {
value = v;
} else if (double.tryParse('$value') case final double v) {
value = v;
} else {
value = switch (value) {
'true' => true,
'false' => false,
'null' => null,
_ => value,
};
}
if (mapped[key] case null) {
mapped[key] = value;
return;
}
// add to existing list of values
// ignore: strict_raw_type
if (mapped[key] case final Iterable list) {
mapped[key] = list.followedBy([value]);
return;
}
// starts a new list
mapped[key] = [mapped[key], value];
}
var pathIsParsed = false;
for (var i = 0; i < args.length; i++) {
final arg = args[i];
if (!arg.startsWith('-')) {
if (pathIsParsed) {
rest.add(arg);
} else {
path.add(arg);
}
continue;
}
if (!pathIsParsed) {
pathIsParsed = true;
}
if (arg.startsWith(RegExp(r'-\w+'))) {
var key = arg.substring(1);
String? value;
if (key.split('=') case [final k, final v]) {
key = k;
value = v;
} else if (i + 1 < args.length) {
value = switch (args[i + 1]) {
final String value when !value.startsWith('-') => value,
_ => null,
};
}
final keys = key.split('');
if (value != null) {
abbr[keys.removeLast()] = value;
i++;
}
for (final alias in keys) {
abbr[alias] = true;
}
continue;
}
if (arg.split('=') case [final key, final value]) {
add(key, value);
continue;
}
if (arg.split('--no-') case [_, final key]) {
mapped[key] = false;
continue;
}
final key = arg.substring(2);
if (i + 1 < args.length) {
if (args[i + 1] case final String value when !value.startsWith('-')) {
add(key, value);
i++;
continue;
}
}
// Standalone flag e.g. --flag
mapped[key] = true;
}
return Args._(
args: mapped,
rest: rest,
path: path,
abbr: abbr,
original: original,
rawArgs: [
for (final arg in original)
if (!path.contains(arg)) arg,
],
);
}