formio.js icon indicating copy to clipboard operation
formio.js copied to clipboard

FIO-4112: integrate core validation and process/processor arch into renderer

Open brendanbond opened this issue 2 years ago • 0 comments

Link to Jira Ticket

https://formio.atlassian.net/browse/FIO-4112

Description

formio/core:21 introduces both

  • the idea of a process - such as "submit" or "change" - that will serve to ready data for various processes like form submission; and
  • the idea of a processor - such as "validate", "encrypt", or "calculateValue" - that, given a form JSON and a data object, will serve as the modular building blocks for the various processes.

This PR attempts to incrementally integrate this concept by attempting to replace the renderer's Validator validations in the existing checkData and checkValidity pipelines with top-down calls to processSync, a synchronous version of the core library's process method. Now, rather than rely on the components to validate themselves, we rely on the form JSON and it's corresponding submission data to validate in one pass.

There were some challenges with the integration process, particularly around Edit Grids and Nested Forms (especially when combined), and some of the API here is clunky. For example, you'll see something crazy in the after array passed to processSync such as

const errors = processSync({
      process: 'change',
      components,
      instances: this.childComponentsMap,
      data: data,
      after: [
        ({ component, path, errors }) => {
          const interpolatedErrors = errors.map((error) => {
            const { errorKeyOrMessage, context } = error;
            const toInterpolate = component.errors && component.errors[errorKeyOrMessage] ? component.errors[errorKeyOrMessage] : errorKeyOrMessage;
            return { ...error, message: unescapeHTML(this.t(toInterpolate, context)), context: { ...context } };
          });
          if (this._parentPath) {
            path = `${this._parentPath}${path}`;
          }
          const componentInstance = this.childComponentsMap[path];
          let isDirty = false;
          if (componentInstance?.options.alwaysDirty || flags.dirty) {
            isDirty = true;
          }
          if (flags.fromSubmission && componentInstance?.hasValue(data)) {
            isDirty = true;
          }
          componentInstance?.setDirty(isDirty);
          componentInstance?.setComponentValidity(interpolatedErrors, isDirty, flags.silentCheck);
          return [];
        }
      ]
    });
    return errors.length === 0;

repeated fairly often. This is because at each point processSync is called, oftentimes an entirely different set of logics are required to then push the requisite changes to the DOM. My hope is that this will clean itself up as we migrate some of the renderer's other logical pathways (e.g. DOM reconciliation) to the new process/processor API.

Dependencies

formio/core:21 formio/core:22

How has this PR been tested?

This PR has a very, very broad surface area, which makes it hard to test everything manually to a degree that might indicate edge case or corner cases that have been missed. However, automated tests are passing, so it's a start.

Checklist:

  • [x] I have commented my code, particularly in hard-to-understand areas
  • [ ] I have made corresponding changes to the documentation (if applicable)
  • [x] My changes generate no new warnings
  • [ ] My changes include tests that prove my fix is effective (or that my feature works as intended)
  • [x] New and existing unit/integration tests pass locally with my changes
  • [x] Any dependent changes have corresponding PRs that are listed above

brendanbond avatar Aug 15 '23 19:08 brendanbond