async validateAsync()

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;
    }