Repository navigation
Closed
Labels
package:code_buildertype-enhancementA request for a change that isn't a bugA request for a change that isn't a bug
Description
Problem & Motivation
code_builder currently provides Expression.cascade(String name), which emits this..{name}. While basic cascades can be chained with .assign(value) (e.g. expr.cascade('prop').assign(val)), several standard Dart cascade features and ergonomic patterns are missing:
- Null-Aware Cascades (
?..):
Dart supports null-aware cascades (target?..prop = val), butcode_builderhas nonullSafeCascade/nullAwareCascademethod (despite supportingnullSafeProperty?.andnullSafeSpread...?). - Cascade Index Operator (
..[key] = valueand?..[key] = value):
Setting map/list elements via cascade (map..['key'] = value) cannot be represented via AST nodes;refer('map').index(k).assign(v)emitsmap[k] = vrather thanmap..[k] = v. - Fluent Ergonomics (
cascadeAssign,cascadeInvoke,cascadeAssigns):
In generators that configure multiple properties on an instantiated object (such as JSON deserializers), authors currently write.cascade('prop1').assign(v1).cascade('prop2').assign(v2). Convenience helpers for assignment and invocation reduce boilerplate.
Proposed API
extension CascadeExpressionExtension on Expression {
/// Returns `this..{name}`.
Expression cascade(String name);
/// Returns `this?..{name}` (null-aware cascade).
Expression nullSafeCascade(String name);
/// Returns `this..[{index}]`.
Expression cascadeIndex(Expression index);
/// Returns `this?..[{index}]`.
Expression nullSafeCascadeIndex(Expression index);
/// Returns `this..{name} = {value}`.
Expression cascadeAssign(String name, Expression value) =>
cascade(name).assign(value);
/// Returns `this?..{name} = {value}`.
Expression nullSafeCascadeAssign(String name, Expression value) =>
nullSafeCascade(name).assign(value);
/// Returns `this..{name}({positionalArguments}, {namedArguments})`.
Expression cascadeInvoke(
String name, [
Iterable<Expression> positionalArguments = const [],
Map<String, Expression> namedArguments = const {},
List<Reference> typeArguments = const [],
]) =>
cascade(name).call(positionalArguments, namedArguments, typeArguments);
/// Chains multiple property assignments on this cascade receiver.
Expression cascadeAssigns(Map<String, Expression> assignments) =>
assignments.entries.fold<Expression>(
this,
(target, entry) => target.cascadeAssign(entry.key, entry.value),
);
}Example Usage
final ctor = refer('Order').newInstanceNamed('custom', [
refer('json').index(literalString('category')).asA(refer('String')),
]);
final result = ctor.cascadeAssigns({
'count': refer('json').index(literalString('count')).asA(refer('num?')).nullSafeProperty('toInt').call([]),
'isRushed': refer('json').index(literalString('isRushed')).asA(refer('bool?')),
});
// Emits:
// Order.custom(json['category'] as String)
// ..count = (json['count'] as num?)?.toInt()
// ..isRushed = json['isRushed'] as bool?;Metadata
Metadata
Assignees
Labels
package:code_buildertype-enhancementA request for a change that isn't a bugA request for a change that isn't a bug
Activity
refactor: migrate TypeHelpers to code_builder AST expressions
[code_builder] Add null-aware cascades, cascade index, and fluent cas…
refactor(json_serializable): migrate codegen to `code_builder` AST (#…