Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/error/FieldError.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getComponentErrorField } from 'process/validation/util';
import { ValidationContext } from 'types';
import { getComponentErrorField } from 'utils/formUtil';

type FieldErrorContext = ValidationContext & {
field?: string;
Expand Down
17 changes: 8 additions & 9 deletions src/modules/jsonlogic/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BaseEvaluator, EvaluatorOptions } from 'utils';
import { normalizeContext } from 'utils/formUtil';
import { jsonLogic } from './jsonLogic';
import { BaseEvaluator, EvaluatorOptions, EvaluatorContext } from 'utils/Evaluator';
export class JSONLogicEvaluator extends BaseEvaluator {
public static evaluate(
func: any,
Expand All @@ -24,12 +25,6 @@ export class JSONLogicEvaluator extends BaseEvaluator {
}
}

export type EvaluatorContext = {
evalContext?: (context: any) => any;
instance?: any;
[key: string]: any;
};

export type EvaluatorFn = (context: EvaluatorContext) => any;

export function evaluate(
Expand All @@ -40,7 +35,9 @@ export function evaluate(
options: EvaluatorOptions = {},
) {
const { evalContext, instance } = context;
const evalContextValue = evalContext ? evalContext(context) : context;
const evalContextValue = evalContext
? evalContext(normalizeContext(context))
: normalizeContext(context);
if (evalContextFn) {
evalContextFn(evalContextValue);
}
Expand All @@ -63,7 +60,9 @@ export function interpolate(
evalContextFn?: EvaluatorFn,
): string {
const { evalContext, instance } = context;
const evalContextValue = evalContext ? evalContext(context) : context;
const evalContextValue = evalContext
? evalContext(normalizeContext(context))
: normalizeContext(context);
if (evalContextFn) {
evalContextFn(evalContextValue);
}
Expand Down
9 changes: 5 additions & 4 deletions src/process/__tests__/process.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
skipValidForLogicallyHiddenComp,
skipValidWithHiddenParentComp,
} from './fixtures';
import { get } from 'lodash';
import _ from 'lodash';

/*
describe('Process Tests', () => {
Expand Down Expand Up @@ -959,6 +959,7 @@ describe('Process Tests', function () {

const errors: any = [];
const context = {
_,
form,
submission,
data: submission.data,
Expand Down Expand Up @@ -1114,8 +1115,8 @@ describe('Process Tests', function () {
submission.data = context.data;
context.processors = ProcessTargets.evaluator;
processSync(context);
assert.equal(get(context.submission.data, 'form1.data.form.data.textField'), 'one 1');
assert.equal(get(context.submission.data, 'form1.data.form.data.textField1'), 'two 2');
assert.equal(_.get(context.submission.data, 'form1.data.form.data.textField'), 'one 1');
assert.equal(_.get(context.submission.data, 'form1.data.form.data.textField1'), 'two 2');
});

it('should remove submission data not in a nested form definition', async function () {
Expand Down Expand Up @@ -3437,7 +3438,7 @@ describe('Process Tests', function () {
});
});

it('Should allow the submission to go through without errors if there is no the subform reference value', async function () {
it('Should allow the submission to go through without errors if there is no subform reference value', async function () {
const form = {
_id: '66bc5cff7ca1729623a182db',
title: 'form2',
Expand Down
5 changes: 4 additions & 1 deletion src/process/calculation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ProcessorInfo,
} from 'types';
import { set } from 'lodash';
import { normalizeContext } from 'utils/formUtil';

export const shouldCalculate = (context: CalculationContext): boolean => {
const { component, config } = context;
Expand All @@ -23,7 +24,9 @@ export const calculateProcessSync: ProcessorFnSync<CalculationScope> = (
if (!shouldCalculate(context)) {
return;
}
const evalContextValue = evalContext ? evalContext(context) : context;
const evalContextValue = evalContext
? evalContext(normalizeContext(context))
: normalizeContext(context);
evalContextValue.value = value || null;
if (!scope.calculated) scope.calculated = [];
const newValue = JSONLogicEvaluator.evaluate(component.calculateValue, evalContextValue, 'value');
Expand Down
10 changes: 4 additions & 6 deletions src/process/clearHidden.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
ProcessorFnSync,
ConditionsScope,
} from 'types';
import { getComponentAbsolutePath } from 'utils/formUtil';

type ClearHiddenScope = ProcessorScope & {
clearHidden: {
Expand All @@ -19,7 +18,6 @@ type ClearHiddenScope = ProcessorScope & {
*/
export const clearHiddenProcess: ProcessorFnSync<ClearHiddenScope> = (context) => {
const { component, data, value, scope, path } = context;
const absolutePath = getComponentAbsolutePath(component) || path;

// No need to unset the value if it's undefined
if (value === undefined) {
Expand All @@ -32,18 +30,18 @@ export const clearHiddenProcess: ProcessorFnSync<ClearHiddenScope> = (context) =

// Check if there's a conditional set for the component and if it's marked as conditionally hidden
const isConditionallyHidden = (scope as ConditionsScope).conditionals?.find((cond) => {
return absolutePath === cond.path && cond.conditionallyHidden;
return path === cond.path && cond.conditionallyHidden;
});

const shouldClearValueWhenHidden =
!component.hasOwnProperty('clearOnHide') || component.clearOnHide;

if (
shouldClearValueWhenHidden &&
(isConditionallyHidden || component.hidden || component.ephemeralState?.conditionallyHidden)
(isConditionallyHidden || component.hidden || component.scope?.conditionallyHidden)
) {
unset(data, absolutePath);
scope.clearHidden[absolutePath] = true;
unset(data, path);
scope.clearHidden[path] = true;
}
};

Expand Down
10 changes: 4 additions & 6 deletions src/process/conditions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
ProcessorInfo,
ConditionsContext,
} from 'types';
import { registerEphemeralState } from 'utils';
import { setComponentScope } from 'utils/formUtil';
import {
checkCustomConditional,
checkJsonConditional,
Expand All @@ -15,7 +15,6 @@ import {
isSimpleConditional,
isJSONConditional,
} from 'utils/conditions';
import { getComponentAbsolutePath } from 'utils/formUtil';

const hasCustomConditions = (context: ConditionsContext): boolean => {
const { component } = context;
Expand Down Expand Up @@ -85,24 +84,23 @@ export type ConditionallyHidden = (context: ConditionsContext) => boolean;

export const conditionalProcess = (context: ConditionsContext, isHidden: ConditionallyHidden) => {
const { scope, path, component } = context;
const absolutePath = getComponentAbsolutePath(component) || path;
if (!hasConditions(context)) {
return;
}

if (!scope.conditionals) {
scope.conditionals = [];
}
let conditionalComp = scope.conditionals.find((cond) => cond.path === absolutePath);
let conditionalComp = scope.conditionals.find((cond) => cond.path === path);
if (!conditionalComp) {
conditionalComp = { path: absolutePath, conditionallyHidden: false };
conditionalComp = { path, conditionallyHidden: false };
scope.conditionals.push(conditionalComp);
}

conditionalComp.conditionallyHidden =
conditionalComp.conditionallyHidden || isHidden(context) === true;
if (conditionalComp.conditionallyHidden) {
registerEphemeralState(context.component, 'conditionallyHidden', true);
setComponentScope(component, 'conditionallyHidden', true);
}
};

Expand Down
6 changes: 4 additions & 2 deletions src/process/defaultValue/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
DefaultValueContext,
} from 'types';
import { set, has } from 'lodash';
import { getComponentKey } from 'utils/formUtil';
import { getComponentKey, normalizeContext } from 'utils/formUtil';

export const hasCustomDefaultValue = (context: DefaultValueContext): boolean => {
const { component } = context;
Expand Down Expand Up @@ -48,7 +48,9 @@ export const customDefaultValueProcessSync: ProcessorFnSync<ConditionsScope> = (
}
let defaultValue = null;
if (component.customDefaultValue) {
const evalContextValue = evalContext ? evalContext(context) : context;
const evalContextValue = evalContext
? evalContext(normalizeContext(context))
: normalizeContext(context);
evalContextValue.value = null;
defaultValue = JSONLogicEvaluator.evaluate(
component.customDefaultValue,
Expand Down
6 changes: 4 additions & 2 deletions src/process/fetch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from 'types';
import { get, set } from 'lodash';
import { Evaluator } from 'utils';
import { getComponentKey } from 'utils/formUtil';
import { getComponentKey, normalizeContext } from 'utils/formUtil';

export const shouldFetch = (context: FetchContext): boolean => {
const { component, config } = context;
Expand Down Expand Up @@ -38,7 +38,9 @@ export const fetchProcess: ProcessorFn<FetchScope> = async (context: FetchContex
return;
}
if (!scope.fetched) scope.fetched = {};
const evalContextValue = evalContext ? evalContext(context) : context;
const evalContextValue = evalContext
? evalContext(normalizeContext(context))
: normalizeContext(context);
const url = Evaluator.interpolateString(get(component, 'fetch.url', ''), evalContextValue);
if (!url) {
return;
Expand Down
1 change: 0 additions & 1 deletion src/process/filter/__tests__/filter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ describe('Filter processor', function () {
type: 'editgrid',
key: 'editGrid',
input: true,
path: 'editGrid',
components: [
{
type: 'textfield',
Expand Down
16 changes: 7 additions & 9 deletions src/process/filter/index.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,44 @@
import { FilterContext, FilterScope, ProcessorFn, ProcessorFnSync, ProcessorInfo } from 'types';
import { set } from 'lodash';
import { Utils } from 'utils';
import { get, isObject } from 'lodash';
import { getComponentAbsolutePath } from 'utils/formUtil';
import { getModelType } from 'utils/formUtil';
export const filterProcessSync: ProcessorFnSync<FilterScope> = (context: FilterContext) => {
const { scope, component, path } = context;
const { value } = context;
const absolutePath = getComponentAbsolutePath(component) || path;
if (!scope.filter) scope.filter = {};
if (value !== undefined) {
const modelType = Utils.getModelType(component);
const modelType = getModelType(component);
switch (modelType) {
case 'dataObject':
scope.filter[absolutePath] = {
scope.filter[path] = {
compModelType: modelType,
include: true,
value: { data: {} },
};
break;
case 'nestedArray':
scope.filter[absolutePath] = {
scope.filter[path] = {
compModelType: modelType,
include: true,
value: [],
};
break;
case 'nestedDataArray':
scope.filter[absolutePath] = {
scope.filter[path] = {
compModelType: modelType,
include: true,
value: Array.isArray(value) ? value.map((v) => ({ ...v, data: {} })) : [],
};
break;
case 'object':
scope.filter[absolutePath] = {
scope.filter[path] = {
compModelType: modelType,
include: true,
value: component.type === 'address' ? false : {},
};
break;
default:
scope.filter[absolutePath] = {
scope.filter[path] = {
compModelType: modelType,
include: true,
};
Expand Down
10 changes: 4 additions & 6 deletions src/process/hideChildren.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,24 @@ import {
ConditionsScope,
ProcessorFn,
} from 'types';
import { registerEphemeralState } from 'utils';
import { getComponentAbsolutePath } from 'utils/formUtil';
import { setComponentScope } from 'utils/formUtil';

/**
* This processor function checks components for the `hidden` property and, if children are present, sets them to hidden as well.
*/
export const hideChildrenProcessor: ProcessorFnSync<ConditionsScope> = (context) => {
const { component, path, parent, scope } = context;
const absolutePath = getComponentAbsolutePath(component) || path;
// Check if there's a conditional set for the component and if it's marked as conditionally hidden
const isConditionallyHidden = scope.conditionals?.find((cond) => {
return absolutePath === cond.path && cond.conditionallyHidden;
return path === cond.path && cond.conditionallyHidden;
});

if (!scope.conditionals) {
scope.conditionals = [];
}

if (isConditionallyHidden || component.hidden || parent?.ephemeralState?.conditionallyHidden) {
registerEphemeralState(component, 'conditionallyHidden', true);
if (isConditionallyHidden || component.hidden || parent?.scope?.conditionallyHidden) {
setComponentScope(component, 'conditionallyHidden', true);
}
};

Expand Down
24 changes: 11 additions & 13 deletions src/process/populate/index.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
import { get, set } from 'lodash';
import { set } from 'lodash';
import { PopulateContext, PopulateScope, ProcessorFnSync } from 'types';
import { componentPath, getContextualRowPath, getModelType } from 'utils/formUtil';
import { getModelType } from 'utils/formUtil';

// This processor ensures that a "linked" row context is provided to every component.
export const populateProcessSync: ProcessorFnSync<PopulateScope> = (context: PopulateContext) => {
const { component, path, scope } = context;
const { component, path, scope, value } = context;
const { data } = scope;
const compDataPath = componentPath(component, getContextualRowPath(component, path));
const compData: any = get(data, compDataPath);
if (!scope.populated) scope.populated = [];
switch (getModelType(component)) {
case 'nestedArray':
if (!compData || !compData.length) {
set(data, compDataPath, [{}]);
scope.row = get(data, compDataPath)[0];
if (!value || !value.length) {
const newValue = [{}];
set(data, path, newValue);
scope.row = newValue[0];
scope.populated.push({
path,
row: get(data, compDataPath)[0],
});
}
break;
case 'dataObject':
case 'object':
if (!compData || typeof compData !== 'object') {
set(data, compDataPath, {});
scope.row = get(data, compDataPath);
if (!value || typeof value !== 'object') {
const newValue = {};
set(data, value, newValue);
scope.row = newValue;
scope.populated.push({
path,
row: get(data, compDataPath),
});
}
break;
Expand Down
Loading