sequentialComponentContent function
String
sequentialComponentContent(
- ServerLifecycleComponent component,
- String formatter(
- Spec
- required String className,
- required String interfaceName,
- required String resultType,
- required String methodName,
- required List<
ServerLifecycleComponentMethod> methods, - required String listName,
- required String itemName,
- required String shortCircuitOn,
- required String fallthrough,
Builds the class for a lifecycle role that runs a sequence of component methods and returns early on the first short-circuiting result.
Guards and middleware share this shape exactly — they differ only in naming, in which result getter ends the loop, and in the result returned when nothing short-circuits. The remaining roles (interceptor, exception catcher, wrapper) have genuinely different shapes and keep their own makers.
The generated class looks like:
class FooGuard implements Guard {
const FooGuard(this.di);
final DI di;
@override
Future<GuardResult> protect(Context context) async {
final component = Foo();
final guards = <FutureOr<GuardResult> Function()>[ ... ];
for (final guard in guards) {
final result = await switch (guard()) { ... };
if (result.isBlock) return result;
}
return const GuardResult.pass();
}
}
Implementation
String sequentialComponentContent(
ServerLifecycleComponent component,
String Function(Spec) formatter, {
required String className,
required String interfaceName,
required String resultType,
required String methodName,
required List<ServerLifecycleComponentMethod> methods,
required String listName,
required String itemName,
/// Getter on the result that ends the loop early, e.g. `isBlock`.
required String shortCircuitOn,
/// Const constructor returned when nothing short-circuits, e.g. `pass`.
required String fallthrough,
}) {
final (:positioned, :named) = getParams(
component.params,
defaultExpression: createGetFromDi(),
useField: true,
);
final parameters = createConstructorParameters(component.params);
final fields = createFields(component.params);
final generics = createGenerics(component.wrapperGenericTypes);
final clazz = Class(
(p) => p
..name = className
..implements.add(refer(interfaceName))
..constructors.add(
Constructor(
(p) => p
..constant = true
..requiredParameters.add(
Parameter(
(p) => p
..name = 'di'
..toThis = true
..named = false,
),
)
..optionalParameters.addAll(parameters),
),
)
..types.addAll(generics)
..fields.add(
Field(
(p) => p
..type = refer('DI')
..name = 'di'
..modifier = FieldModifier.final$,
),
)
..fields.addAll(fields)
..methods.add(
Method(
(p) => p
..name = methodName
..returns = refer('Future<$resultType>')
..modifier = MethodModifier.async
..annotations.add(refer('override'))
..requiredParameters.add(
Parameter(
(p) => p
..name = 'context'
..type = refer('Context'),
),
)
..body = Block.of([
declareFinal('component')
.assign(
refer(
component.instantiatedName,
).newInstance(positioned, named),
)
.statement,
const Code('\n'),
declareFinal(listName)
.assign(
literalList([
...createComponentMethods(methods),
], refer('FutureOr<$resultType> Function()')),
)
.statement,
const Code('\n'),
forInLoop(
declaration: declareFinal(itemName),
iterable: refer(listName),
body: Block.of([
declareFinal('result')
.assign(
createSwitchPattern(refer(itemName).call([]), {
declareFinal(
'future',
type: refer('Future<$resultType>'),
): refer(
'future',
),
declareFinal(
'result',
type: refer(resultType),
): refer(
'Future',
).property('value').call([refer('result')]),
}).awaited,
)
.statement,
const Code('\n'),
ifStatement(
refer('result').property(shortCircuitOn),
body: refer('result').returned.statement,
).code,
]),
).code,
const Code('\n'),
declareConst(
resultType,
).property(fallthrough).call([]).returned.statement,
]),
),
),
);
return formatter(clazz);
}