in packages/bonito-core/src/form/internal/form-impl.ts [380:465]
async validateAsync(
snapshot: ValidationSnapshot<V>,
opts: ValidationOpts
): Promise<ValidationSnapshot<V>> {
const validatingEntries = [];
const validationPromises = [];
const newValidationStatuses: { [name in keyof V]?: ValidationStatus } =
{};
// Call validateAsync() for each entry but don't block
// on completion
for (const entry of this.allEntries()) {
const entryName = entry.name as ParameterName<V>;
if (entry instanceof AbstractParameter) {
if (snapshot.entryStatus[entryName]?.level === "error") {
// Don't run async validation if sync validation
// has already failed for this parameter
continue;
}
validatingEntries.push(entry);
validationPromises.push(
entry.validateAsync().then((status) => {
status.forced = opts.force;
newValidationStatuses[entryName] = status;
return status;
})
);
} else if (entry instanceof SubForm) {
validatingEntries.push(entry);
validationPromises.push(
entry
.validateAsync(entry.form.validationSnapshot, opts)
.then((snapshot) => {
newValidationStatuses[entryName] =
snapshot.overallStatus;
return snapshot.overallStatus;
})
);
}
}
await Promise.all(validationPromises);
if (this._checkAndCancelValidationSnapshot(snapshot, opts.force)) {
return snapshot;
}
// All entries have validated
for (const entry of validatingEntries) {
const entryName = entry.name as ParameterName<V>;
if (snapshot.entryStatus[entryName]?.level !== "error") {
snapshot.entryStatus[entryName] =
newValidationStatuses[entryName];
}
}
// Run overall form onValidateAsync callback
if (this.onValidateAsync) {
snapshot.onValidateAsyncStatus = await this.onValidateAsync(
snapshot.values
);
snapshot.onValidateAsyncStatus.forced = opts.force;
}
snapshot.asyncValidationComplete = true;
if (this._checkAndCancelValidationSnapshot(snapshot, opts.force)) {
return snapshot;
}
// This snapshot is done, and is now the current in-effect snapshot
snapshot.validationCompleteDeferred.resolve();
snapshot.updateOverallStatus();
this._validationSnapshot = snapshot;
this._emitValidateEvent(snapshot);
if (!snapshot.overallStatus) {
// Hitting this indicates a bug. This shouldn't ever be undefined
// at this point.
throw new Error("Failed to compute overall validation status");
}
return snapshot;
}