felangel / felangel/mason

feat: [mason_logger] support validation for `prompt`, `promptAny`, and `chooseAny`

Open
#1,550 1 comment 3 reactions 0 assignees View on GitHub
Dominant language
Dart
Stars
1.1k
Forks
113
PR merge metrics
No merged PRs in 30d

Description

**Description**

`Logger` has some user inputs that accept arbitrary data. It can be useful to validate that user input "inline" with a given user input without having to re-prompt the user for an input.

**Requirements**

- [ ] define `Validator` typedef like [Flutter's `FormFieldValidator`](https://api.flutter.dev/flutter/widgets/FormFieldValidator.html).
- [ ] add optional `Validator? validator` parameter to `Logger.prompt`
- [ ] add optional `Validator>? validator` parameter to `Logger.promptAny`
- [ ] add optional `Validator>? validator` parameter to `Logger.chooseAny`

**Additional Context**

> Why these methods?

I think these are the only places a validation makes sense since data types are not very constrained compored to the other inputs.
- `chooseOne` is already very limiting with select one (how would you validate "one" item?).
- `confirm`'s return value is it's "validation" by nature of booleans. "Inline" validation does seem to provide any additional information to the user.

> How would this work?

Take this current validation flow for requiring a compatible dart package name.

```dart
void main(List arguments) {
final value = collectInput();
print(value);
}

String? validate(String value) {
if (value.contains(' ')) return 'Cannot contain spaces';
if (value.contains('.')) return 'Cannot contain dots';
if (value.contains('-')) return 'Cannot contain hyphen';
// descriptive messages
return null;
}

String collectInput() {
Logger logger = Logger();
String value;
String? validation;
do {
var prompt = 'Dart package name';
if (validation != null) {
prompt = 'Dart package name ${red.wrap(validation)}';
}
value = logger.prompt(prompt, defaultValue: 'my_app');
validation = validate(value);
} while (validation != null);

return value;
}
```

Could be reduced to this kind of flow by passing in the validator directly: `validator: validate`

```dart
void main(List arguments) {
final value = collectInput();
print(value);
}

String? validate(String value) {
if (value.contains(' ')) return 'Cannot contain spaces';
if (value.contains('.')) return 'Cannot contain dots';
if (value.contains('-')) return 'Cannot contain hyphen';
return null;
}

String collectInput() {
Logger logger = Logger();
return logger.prompt(
'Dart package name',
defaultValue: 'my_app',
validator: validate,
);
}
```

> How should it look?

I think an "inline" message can use the same style as `Logger.theme.warn`.
```dart
void main(List arguments) {
Logger logger = Logger();
// simulate validation failing
String? validation = logger.theme.warn('Cannot contain spaces');
logger.prompt('Dart package name $validation', defaultValue: 'my_app');
}
```

```
Dart package name Cannot contain spaces (my_app) my app
```

Image

> When should the `validator` function be executed?

If a `validator` is provided, the function executes when the user submits a value. When `validator(value)` returns `null` the value returns as normal to its consumer.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.