Lazy Scalar Resolvers topic
A ScalarResolver is lazy and gives up control to the parser on condition that it must resolve a scalar's type using a custom mapping function. This mapping function will be embedded within the resolved tag itself via a ContentResolver. This is only done to scalars that have the captured tag. Any tag can be captured including the default YAML and failsafe JSON schema tags.
Tip
- Always prefer returning
nullinstead of throwing within the mapping function. Let the parser create a partial scalar using the string content it has parsed. - The parser always resolves the node when it needs it. This need may vary depending on the parsing stage of the node or its parent.
Examples
All examples are meant to provide the gist on how to use the ScalarResolver. They can be found in the example/scalar_resolver.dart file.
BigInt example
Consider a scenario where your integers may overflow the customary 64-bit size used by the built-in int type in Dart. You could annotate them with !!int and provide a custom function that binds itself to that tag.
// The resolver
final resolver = ScalarResolver.onMatch(
integerTag, // `!!int` is exported by this package
contentResolver: BigInt.parse,
toYamlSafe: (value) => '0x${value.toRadixString(16)}',
);
// 36893488147419103231
print(
loadDartObject<BigInt>(
YamlSource.string('!!int 0x1ffffffffffffffff'),
triggers: CustomTriggers(resolvers: [resolver]),
),
);
By default, the toYamlSafe callback is also stripped for built-in Dart types. A Scalar, however, preserves it.
// 0x1ffffffffffffffff
print(
loadYamlNode<Scalar>(
YamlSource.string('!!int 0x1ffffffffffffffff'),
triggers: CustomTriggers(resolvers: [resolver]),
),
);
YAML Range example
YAML is meant to be a human-readable but most (if not all) machines have no such notion. Consider the example below extracted from the YAML spec example 6.19.
%TAG !! tag:example.com,2000:app/
---
!!int 1 - 3 # Interval, not integer
typedef Interval = ({int min, int max});
final specResolver = ScalarResolver<Interval>.onMatch(
integerTag,
contentResolver: (s) {
final [min, max] = s.split('-');
return (min: int.parse(min.trim()), max: int.parse(max.trim()));
},
toYamlSafe: (range) => '${range.min} - ${range.max}',
);
const yaml = '''
%TAG !! tag:example.com,2000:app/
---
!!int 1 - 3 # Interval, not integer
''';
// (min: 1, max: 3)
print(
loadDartObject<Interval>(
yaml,
triggers: CustomTriggers(resolvers: [specResolver]),
),
);
// 1 - 3
print(loadYamlNode(yaml, resolvers: [specResolver]));
DateTime example
This package has no support for inferring a scalar as a DateTime object. You may use any package to achieve this but for simplicity's sake, let's use Dart's internal DateTime implementation.
// Not a suggested naming convention; just a choice
final dateTag = TagShorthand.primary('dart/datetime');
final dateResolver = ScalarResolver<DateTime>.onMatch(
dateTag,
contentResolver: DateTime.parse, // Simple. Not complicated.
toYamlSafe: (date) => date.toString(), // Just for show
);
print(
loadDartObject<DateTime>(
YamlSource.string('$dateTag 19631212 12:12'),
triggers: CustomTriggers(resolvers: [dateResolver]),
),
);
Classes
-
ContentResolver<
O> Lazy Scalar Resolvers -
Resolves a Scalar's parsed content and requires the function to return
nullif mapping fails. This allows the parser to provide a (partial) kind. Avoid throwing within the mapping function. -
ScalarResolver<
O> Lazy Scalar Resolvers -
A resolver for a Scalar. The type emitted by this resolver lives within
the scalar itself or acts as the type inferred when directly parsed as a
Dartobject.