Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/config/lib/src/config/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export 'exceptions.dart';
export 'file_system_options.dart';
export 'multi_config_source.dart';
export 'option_groups.dart';
export 'option_resolution.dart';
export 'option_types.dart';
export 'options.dart';
export 'output_formatting.dart' show formatConfigError;
Expand Down
29 changes: 16 additions & 13 deletions packages/config/lib/src/config/configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'package:collection/collection.dart';

import 'configuration_broker.dart';
import 'exceptions.dart';
import 'option_resolution.dart';
import 'option_resolution_impl.dart';
import 'options.dart';
import 'output_formatting.dart';
import 'source_type.dart';
Expand Down Expand Up @@ -43,7 +43,7 @@ import 'source_type.dart';
/// ```
class Configuration<O extends OptionDefinition> {
final List<O> _options;
final Map<O, OptionResolution> _config;
final Map<O, OptionResolutionImpl> _config;
final List<String> _errors;

/// Creates a configuration with the provided option values.
Expand Down Expand Up @@ -86,7 +86,7 @@ class Configuration<O extends OptionDefinition> {
final Map<O, Object?>? presetValues,
final bool ignoreUnexpectedPositionalArgs = false,
}) : _options = List<O>.from(options),
_config = <O, OptionResolution>{},
_config = <O, OptionResolutionImpl>{},
_errors = <String>[] {
if (argResults == null && args != null) {
argResults = _prepareArgResults(args);
Expand Down Expand Up @@ -118,7 +118,7 @@ class Configuration<O extends OptionDefinition> {
final Map<O, Object?>? presetValues,
final bool ignoreUnexpectedPositionalArgs = false,
}) : _options = List<O>.from(options),
_config = <O, OptionResolution>{},
_config = <O, OptionResolutionImpl>{},
_errors = <String>[] {
if (argResults == null && args != null) {
argResults = _prepareArgResults(args);
Expand Down Expand Up @@ -148,7 +148,8 @@ class Configuration<O extends OptionDefinition> {
} on FormatException catch (e) {
_errors.add(e.message);
for (final o in _options) {
_config[o] = const OptionResolution.error('Previous ArgParser error');
_config[o] =
const OptionResolutionImpl.error('Previous ArgParser error');
}
return null;
}
Expand Down Expand Up @@ -270,7 +271,9 @@ class Configuration<O extends OptionDefinition> {
return resolution.source;
}

OptionResolution _getOptionResolution<V>(final OptionDefinition<V> option) {
OptionResolutionImpl _getOptionResolution<V>(
final OptionDefinition<V> option,
) {
if (!_options.contains(option)) {
throw ArgumentError(
'${option.qualifiedString()} is not part of this configuration');
Expand Down Expand Up @@ -302,10 +305,10 @@ class Configuration<O extends OptionDefinition> {
final orderedOpts = _options.sorted((final a, final b) =>
(a.option.argPos ?? -1).compareTo(b.option.argPos ?? -1));

final optionGroups = <OptionGroup, Map<O, OptionResolution>>{};
final optionGroups = <OptionGroup, Map<O, OptionResolutionImpl>>{};

for (final opt in orderedOpts) {
OptionResolution resolution;
OptionResolutionImpl resolution;
try {
if (presetValues != null && presetValues.containsKey(opt)) {
resolution = _resolvePresetValue(opt, presetValues[opt]);
Expand Down Expand Up @@ -336,7 +339,7 @@ class Configuration<O extends OptionDefinition> {
// Represents an option resolution that depends on another option
// whose resolution failed, so this resolution fails in turn.
// Not adding to _errors to avoid double reporting.
resolution = OptionResolution.error(e.message);
resolution = OptionResolutionImpl.error(e.message);
}

_config[opt] = resolution;
Expand All @@ -351,21 +354,21 @@ class Configuration<O extends OptionDefinition> {
}
}

OptionResolution _resolvePresetValue(
OptionResolutionImpl _resolvePresetValue(
final O option,
final Object? value,
) {
final resolution = value == null
? const OptionResolution.noValue()
: OptionResolution(value: value, source: ValueSourceType.preset);
? const OptionResolutionImpl.noValue()
: OptionResolutionImpl(value: value, source: ValueSourceType.preset);

final error = option.option.validateOptionValue(value);
if (error != null) return resolution.copyWithError(error);
return resolution;
}

void _validateGroups(
final Map<OptionGroup, Map<O, OptionResolution>> optionGroups,
final Map<OptionGroup, Map<O, OptionResolutionImpl>> optionGroups,
) {
optionGroups.forEach((final group, final optionResolutions) {
final error = group.validateValues(optionResolutions);
Expand Down
61 changes: 17 additions & 44 deletions packages/config/lib/src/config/option_resolution.dart
Original file line number Diff line number Diff line change
@@ -1,51 +1,24 @@
import 'source_type.dart';

final class OptionResolution<V> {
final String? stringValue;
final V? value;
final String? error;
final ValueSourceType source;

const OptionResolution._({
required this.source,
this.stringValue,
this.value,
this.error,
});

const OptionResolution({
required this.source,
this.stringValue,
this.value,
}) : error = null;

const OptionResolution.noValue()
: source = ValueSourceType.noValue,
stringValue = null,
value = null,
error = null;

const OptionResolution.error(this.error)
: source = ValueSourceType.noValue,
stringValue = null,
value = null;

OptionResolution<V> copyWithValue(final V newValue) => OptionResolution._(
source: source,
stringValue: stringValue,
value: newValue,
error: error,
);

OptionResolution<V> copyWithError(final String error) => OptionResolution._(
source: source,
stringValue: stringValue,
value: value,
error: error,
);
/// Describes the resolution of a configuration option.
abstract class OptionResolution<V> {
const OptionResolution();

/// The resolved value of the option, or null if there was no value
/// or if there was an error.
V? get value;

/// The error message if the option was not successfully resolved.
String? get error;

/// The source type of the option's value.
ValueSourceType get source;

/// Whether the option was not successfully resolved.
bool get hasError => error != null;

/// Whether the option has a proper value (without errors).
bool get hasValue => source != ValueSourceType.noValue && error == null;
bool get hasValue => source != ValueSourceType.noValue && !hasError;

/// Whether the option has a value that was specified explicitly (not default).
bool get isSpecified => hasValue && source != ValueSourceType.defaultValue;
Expand Down
55 changes: 55 additions & 0 deletions packages/config/lib/src/config/option_resolution_impl.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import 'option_resolution.dart';
import 'source_type.dart';

final class OptionResolutionImpl<V> extends OptionResolution<V> {
final String? stringValue;

@override
final V? value;

@override
final String? error;

@override
final ValueSourceType source;

const OptionResolutionImpl._({
required this.source,
this.stringValue,
this.value,
this.error,
});

const OptionResolutionImpl({
required this.source,
this.stringValue,
this.value,
}) : error = null;

const OptionResolutionImpl.noValue()
: source = ValueSourceType.noValue,
stringValue = null,
value = null,
error = null;

const OptionResolutionImpl.error(this.error)
: source = ValueSourceType.noValue,
stringValue = null,
value = null;

OptionResolutionImpl<V> copyWithValue(final V newValue) =>
OptionResolutionImpl._(
source: source,
stringValue: stringValue,
value: newValue,
error: error,
);

OptionResolutionImpl<V> copyWithError(final String error) =>
OptionResolutionImpl._(
source: source,
stringValue: stringValue,
value: value,
error: error,
);
}
Loading