diff --git a/src/process/processOne.ts b/src/process/processOne.ts
index 941e8ac2..50d2ad83 100644
--- a/src/process/processOne.ts
+++ b/src/process/processOne.ts
@@ -9,7 +9,7 @@ export function dataValue(component: Component, row: any) {
}
export async function processOne(context: ProcessorsContext) {
- const { processors, component } = context;
+ const { processors, component, path } = context;
// Create a getter for `value` that is always derived from the current data object
if (typeof context.value === 'undefined') {
Object.defineProperty(context, 'value', {
@@ -22,8 +22,18 @@ export async function processOne(context: ProcessorsContext(context: ProcessorsContext(context: ProcessorsContext) {
- const { processors, component } = context;
+ const { processors, component, path } = context;
// Create a getter for `value` that is always derived from the current data object
if (typeof context.value === 'undefined') {
Object.defineProperty(context, 'value', {
@@ -49,8 +59,17 @@ export function processOneSync(context: ProcessorsContextsome text
",
- "label": "Content",
- "key": "content",
- "type": "content"
- },
- {
- "label": "Text Field",
- "key": "textField",
- "type": "textfield",
- "input": true
- },
- {
- "label": "Number",
- "key": "number",
- "type": "number",
- "input": true
- }
-]
diff --git a/src/utils/__tests__/formUtil.test.ts b/src/utils/__tests__/formUtil.test.ts
index 8d63350d..5e004c94 100644
--- a/src/utils/__tests__/formUtil.test.ts
+++ b/src/utils/__tests__/formUtil.test.ts
@@ -1,15 +1,13 @@
-import * as fs from 'fs';
+import fs from 'fs';
import get from 'lodash/get';
import { expect } from 'chai';
-import { Component, HasChildComponents, TableComponent } from 'types';
+import { Component } from 'types';
import {
getContextualRowData,
eachComponentDataAsync,
isComponentDataEmpty,
- eachComponent,
eachComponentData,
- isLayoutComponent,
findComponent,
findComponents,
getComponent,
@@ -19,19 +17,6 @@ import {
getModelType,
} from '../formUtil';
-const components = JSON.parse(fs.readFileSync(__dirname + '/fixtures/components.json').toString());
-const components2 = JSON.parse(
- fs.readFileSync(__dirname + '/fixtures/components2.json').toString(),
-);
-const components3 = JSON.parse(
- fs.readFileSync(__dirname + '/fixtures/components3.json').toString(),
-);
-const components4 = JSON.parse(
- fs.readFileSync(__dirname + '/fixtures/components4.json').toString(),
-);
-const components5 = JSON.parse(
- fs.readFileSync(__dirname + '/fixtures/components5.json').toString(),
-);
const writtenNumber = (n: number | null) => {
switch (n) {
case 1:
@@ -55,440 +40,18 @@ const writtenNumber = (n: number | null) => {
}
};
-describe('formUtil', function () {
- describe('eachComponent', function () {
- it('should iterate through nested components in the right order', function () {
- let n = 1;
- eachComponent(components, (component: Component) => {
- expect((component as any).order).to.equal(n);
- n += 1;
- });
- });
-
- it('should include layouts components if provided', function () {
- let numComps = 0;
- let numLayout = 0;
- eachComponent(
- components,
- (component: Component) => {
- if (isLayoutComponent(component)) {
- numLayout++;
- } else {
- numComps++;
- }
- },
- true,
- );
- expect(numLayout).to.be.equal(3);
- expect(numComps).to.be.equal(8);
- });
-
- it('Should provide the paths to all of the components', function () {
- const paths = [
- 'one',
- 'parent1',
- 'two',
- 'parent2',
- 'three',
- '',
- 'four',
- 'five',
- 'six',
- 'seven',
- 'eight',
- ];
- const testPaths: string[] = [];
- eachComponent(
- components,
- (component: Component, path: string) => {
- testPaths.push(path);
- },
- true,
- );
- expect(paths).to.deep.equal(testPaths);
- });
-
- it('Should iterate over each component given a flat components array', function () {
- const components = [
- {
- type: 'textfield',
- key: 'textField',
- input: true,
- },
- {
- type: 'textarea',
- key: 'textArea',
- input: true,
- },
- ];
- const rowResults: Map = new Map();
- eachComponent(components, (component: Component, path: string) => {
- rowResults.set(path, component);
- });
- expect(rowResults.size).to.equal(2);
- expect(rowResults.get('textField')).to.deep.equal({
- type: 'textfield',
- key: 'textField',
- input: true,
- });
- expect(rowResults.get('textArea')).to.deep.equal({
- type: 'textarea',
- key: 'textArea',
- input: true,
- });
- });
-
- it('Should iterate over each component with correct pathing given a container component', function () {
- const components = [
- {
- type: 'textfield',
- key: 'textField',
- input: true,
- },
- {
- type: 'container',
- key: 'container',
- input: true,
- components: [
- {
- type: 'textfield',
- key: 'nestedTextField',
- input: true,
- },
- {
- type: 'textarea',
- key: 'nestedTextArea',
- input: true,
- },
- ],
- },
- ];
- const rowResults: Map = new Map();
- eachComponent(
- components,
- (component: Component, path: string) => {
- rowResults.set(path, component);
- },
- true,
- );
- expect(rowResults.size).to.equal(4);
- expect(rowResults.get('textField')).to.deep.equal({
- type: 'textfield',
- key: 'textField',
- input: true,
- });
- expect(rowResults.get('container')).to.deep.equal({
- type: 'container',
- key: 'container',
- input: true,
- components: [
- {
- type: 'textfield',
- key: 'nestedTextField',
- input: true,
- },
- {
- type: 'textarea',
- key: 'nestedTextArea',
- input: true,
- },
- ],
- });
- expect(rowResults.get('container.nestedTextField')).to.deep.equal({
- type: 'textfield',
- key: 'nestedTextField',
- input: true,
- });
- expect(rowResults.get('container.nestedTextArea')).to.deep.equal({
- type: 'textarea',
- key: 'nestedTextArea',
- input: true,
- });
- });
-
- it('Should iterate over each component with correct pathing given a datagrid component', function () {
- const components = [
- {
- type: 'textfield',
- key: 'textField',
- input: true,
- },
- {
- type: 'datagrid',
- key: 'dataGrid',
- input: true,
- components: [
- {
- type: 'textfield',
- key: 'nestedTextField',
- input: true,
- },
- {
- type: 'textarea',
- key: 'nestedTextArea',
- input: true,
- },
- ],
- },
- ];
- const rowResults: Map = new Map();
- eachComponent(
- components,
- (component: Component, path: string) => {
- rowResults.set(path, component);
- },
- true,
- );
- expect(rowResults.size).to.equal(4);
- expect(rowResults.get('textField')).to.deep.equal({
- type: 'textfield',
- key: 'textField',
- input: true,
- });
- expect(rowResults.get('dataGrid')).to.deep.equal({
- type: 'datagrid',
- key: 'dataGrid',
- input: true,
- components: [
- {
- type: 'textfield',
- key: 'nestedTextField',
- input: true,
- },
- {
- type: 'textarea',
- key: 'nestedTextArea',
- input: true,
- },
- ],
- });
- expect(rowResults.get('dataGrid.nestedTextField')).to.deep.equal({
- type: 'textfield',
- key: 'nestedTextField',
- input: true,
- });
- expect(rowResults.get('dataGrid.nestedTextArea')).to.deep.equal({
- type: 'textarea',
- key: 'nestedTextArea',
- input: true,
- });
- });
-
- it("Should iterate over each component with correct pathing given a datagrid's child components", function () {
- const components = [
- {
- type: 'datagrid',
- key: 'dataGrid',
- input: true,
- components: [
- {
- type: 'textfield',
- key: 'nestedTextField',
- input: true,
- },
- {
- type: 'textarea',
- key: 'nestedTextArea',
- input: true,
- },
- ],
- },
- ];
- const rowResults: Map = new Map();
- eachComponent(
- components[0].components,
- (component: Component, path: string) => {
- rowResults.set(path, component);
- },
- true,
- 'dataGrid',
- );
- expect(rowResults.size).to.equal(2);
- expect(rowResults.get('dataGrid.nestedTextField')).to.deep.equal({
- type: 'textfield',
- key: 'nestedTextField',
- input: true,
- });
- expect(rowResults.get('dataGrid.nestedTextArea')).to.deep.equal({
- type: 'textarea',
- key: 'nestedTextArea',
- input: true,
- });
- });
-
- describe('findComponent', function () {
- it('should find correct component in nested structure', function () {
- findComponent(components4, 'four', null, (component: Component) => {
- expect(component.label).to.equal('4');
- });
- });
-
- it('should find correct component in flat structure', function () {
- findComponent(components4, 'one', null, (component: Component) => {
- expect(component.label).to.equal('1');
- });
- });
- });
-
- it('Should be able to find all textfield components', function () {
- const comps = findComponents(components, { type: 'textfield' });
- expect(comps.length).to.equal(6);
- });
-
- it('Should be able to find components with special properties.', function () {
- const comps = findComponents(components3, { 'properties.path': 'a' });
- expect(comps.length).to.equal(4);
- expect(comps[0].key).to.equal('b');
- expect(comps[1].key).to.equal('e');
- expect(comps[2].key).to.equal('j');
- expect(comps[3].key).to.equal('m');
- });
-
- it('Should be able to generate paths based on component types', function () {
- const paths = [
- 'a',
- 'b',
- 'c',
- 'd',
- 'f',
- 'f.g',
- 'f.h',
- 'f.i',
- 'e',
- 'j',
- 'k',
- 'k.n',
- 'k.n.o',
- 'k.n.p',
- 'k.n.q',
- 'k.m',
- 'k.l',
- 'r',
- 'submit',
- 'tagpad',
- 'tagpad.a',
- ];
- const testPaths: string[] = [];
- eachComponent(
- components2,
- (component: Component, path: string) => {
- testPaths.push(path);
- },
- true,
- );
- expect(paths).to.deep.equal(testPaths);
- });
-
- it('Should still provide the correct paths when it is not recursive', function () {
- const paths = [
- 'a',
- 'd',
- 'f',
- 'f.g',
- 'f.h',
- 'f.i',
- 'e',
- 'j',
- 'k',
- 'k.n',
- 'k.n.o',
- 'k.n.p',
- 'k.n.q',
- 'k.m',
- 'k.l',
- 'r',
- 'submit',
- 'tagpad',
- 'tagpad.a',
- ];
- const testPaths: string[] = [];
- eachComponent(components2, (component: Component, path: string) => {
- testPaths.push(path);
- });
- expect(paths).to.deep.equal(testPaths);
- });
-
- it('should be able to block recursion', function () {
- let numComps = 0;
- let numLayout = 0;
- eachComponent(
- components,
- (component: Component) => {
- if (isLayoutComponent(component)) {
- numLayout++;
- } else {
- numComps++;
- }
-
- if (component.type === 'table') {
- let numInTable = 0;
- const tableComponent: TableComponent = component as TableComponent;
- tableComponent.rows.forEach((row: Component[]) => {
- row.forEach((comp: Component) => {
- eachComponent((comp as HasChildComponents).components, () => {
- numInTable++;
- });
- });
- });
- expect(numInTable).to.be.equal(4);
- return true;
- }
- },
- true,
- );
- expect(numLayout).to.be.equal(3);
- expect(numComps).to.be.equal(4);
- });
-
- it('should not include `htmlelement` components when `includeAll` is not provided', function () {
- let htmlComponentsAmount = 0;
- eachComponent(components5, (component: Component) => {
- if (component.type === 'htmlelement') {
- htmlComponentsAmount++;
- }
- });
- expect(htmlComponentsAmount).to.be.equal(0);
- });
-
- it('should include `htmlelement` components when `includeAll` is provided', function () {
- let htmlComponentsAmount = 0;
- eachComponent(
- components5,
- (component: Component) => {
- if (component.type === 'htmlelement') {
- htmlComponentsAmount++;
- }
- },
- true,
- );
- expect(htmlComponentsAmount).to.be.equal(1);
- });
-
- it('should not include `content` components when `includeAll` is not provided', function () {
- let contentComponentsAmount = 0;
- eachComponent(components5, (component: Component) => {
- if (component.type === 'content') {
- contentComponentsAmount++;
- }
- });
- expect(contentComponentsAmount).to.be.equal(0);
- });
-
- it('should include `content` components when `includeAll` is provided', function () {
- let contentComponentsAmount = 0;
- eachComponent(
- components5,
- (component: Component) => {
- if (component.type === 'content') {
- contentComponentsAmount++;
- }
- },
- true,
- );
- expect(contentComponentsAmount).to.be.equal(1);
- });
- });
+const components = JSON.parse(fs.readFileSync(__dirname + '/fixtures/components.json').toString());
+const components2 = JSON.parse(
+ fs.readFileSync(__dirname + '/fixtures/components2.json').toString(),
+);
+const components3 = JSON.parse(
+ fs.readFileSync(__dirname + '/fixtures/components3.json').toString(),
+);
+const components4 = JSON.parse(
+ fs.readFileSync(__dirname + '/fixtures/components4.json').toString(),
+);
+describe('formUtil', function () {
describe('getComponent', function () {
it('should return the correct components', function () {
for (let n = 1; n <= 8; n += 1) {
@@ -2189,4 +1752,34 @@ describe('formUtil', function () {
expect(actual).to.equal(expected);
});
});
+
+ describe('findComponent', function () {
+ it('should find correct component in nested structure', function () {
+ findComponent(components2, 'four', null, (component: Component) => {
+ expect(component.label).to.equal('4');
+ });
+ });
+
+ it('should find correct component in flat structure', function () {
+ findComponent(components4, 'one', null, (component: Component) => {
+ expect(component.label).to.equal('1');
+ });
+ });
+ });
+
+ describe('findComponents', function () {
+ it('Should be able to find all textfield components', function () {
+ const comps = findComponents(components, { type: 'textfield' });
+ expect(comps.length).to.equal(6);
+ });
+
+ it('Should be able to find components with special properties.', function () {
+ const comps = findComponents(components3, { 'properties.path': 'a' });
+ expect(comps.length).to.equal(4);
+ expect(comps[0].key).to.equal('b');
+ expect(comps[1].key).to.equal('e');
+ expect(comps[2].key).to.equal('j');
+ expect(comps[3].key).to.equal('m');
+ });
+ });
});
diff --git a/src/utils/formUtil/__tests__/eachComponent.test.ts b/src/utils/formUtil/__tests__/eachComponent.test.ts
new file mode 100644
index 00000000..94d9beaa
--- /dev/null
+++ b/src/utils/formUtil/__tests__/eachComponent.test.ts
@@ -0,0 +1,1098 @@
+import { expect } from 'chai';
+
+import { eachComponent } from '../eachComponent';
+import { isLayoutComponent } from '../index';
+
+import { Component, TableComponent, HasChildComponents } from 'types';
+
+describe('eachComponent', function () {
+ const components = [
+ {
+ type: 'textfield',
+ key: 'one',
+ order: 1,
+ input: true,
+ },
+ {
+ input: false,
+ key: 'parent1',
+ components: [
+ {
+ type: 'textfield',
+ key: 'two',
+ order: 2,
+ },
+ {
+ input: false,
+ key: 'parent2',
+ columns: [
+ {
+ components: [
+ {
+ type: 'textfield',
+ key: 'three',
+ order: 3,
+ },
+ ],
+ },
+ {
+ components: [
+ {
+ rows: [
+ [
+ {
+ components: [
+ {
+ key: 'four',
+ order: 4,
+ type: 'textfield',
+ },
+ ],
+ },
+ {
+ components: [
+ {
+ key: 'five',
+ order: 5,
+ type: 'textfield',
+ },
+ ],
+ },
+ ],
+ [
+ {
+ components: [
+ {
+ key: 'six',
+ order: 6,
+ type: 'textfield',
+ },
+ ],
+ },
+ {
+ components: [
+ {
+ key: 'seven',
+ order: 7,
+ type: 'textarea',
+ rows: 3,
+ },
+ ],
+ },
+ ],
+ ],
+ type: 'table',
+ },
+ ],
+ },
+ ],
+ type: 'columns',
+ },
+ ],
+ type: 'well',
+ },
+ {
+ key: 'eight',
+ order: 8,
+ type: 'button',
+ input: true,
+ },
+ ];
+ const components2 = [
+ {
+ type: 'textfield',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ validate: {
+ customPrivate: false,
+ custom: '',
+ pattern: '',
+ maxLength: '',
+ minLength: '',
+ required: false,
+ },
+ persistent: true,
+ unique: false,
+ protected: false,
+ defaultValue: '',
+ multiple: false,
+ suffix: '',
+ prefix: '',
+ placeholder: '',
+ key: 'a',
+ label: 'A',
+ inputMask: '',
+ inputType: 'text',
+ tableView: true,
+ input: true,
+ },
+ {
+ lockKey: true,
+ key: 'b',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ type: 'fieldset',
+ components: [
+ {
+ lockKey: true,
+ key: 'c',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ type: 'columns',
+ columns: [
+ {
+ components: [
+ {
+ type: 'textfield',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ validate: {
+ customPrivate: false,
+ custom: '',
+ pattern: '',
+ maxLength: '',
+ minLength: '',
+ required: false,
+ },
+ persistent: true,
+ unique: false,
+ protected: false,
+ defaultValue: '',
+ multiple: false,
+ suffix: '',
+ prefix: '',
+ placeholder: '',
+ key: 'd',
+ label: 'D',
+ inputMask: '',
+ inputType: 'text',
+ tableView: true,
+ input: true,
+ },
+ {
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ type: 'container',
+ persistent: true,
+ protected: false,
+ key: 'f',
+ label: 'F',
+ tableView: true,
+ components: [
+ {
+ type: 'textfield',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ validate: {
+ customPrivate: false,
+ custom: '',
+ pattern: '',
+ maxLength: '',
+ minLength: '',
+ required: false,
+ },
+ persistent: true,
+ unique: false,
+ protected: false,
+ defaultValue: '',
+ multiple: false,
+ suffix: '',
+ prefix: '',
+ placeholder: '',
+ key: 'g',
+ label: 'G',
+ inputMask: '',
+ inputType: 'text',
+ tableView: true,
+ input: true,
+ },
+ {
+ type: 'textfield',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ validate: {
+ customPrivate: false,
+ custom: '',
+ pattern: '',
+ maxLength: '',
+ minLength: '',
+ required: false,
+ },
+ persistent: true,
+ unique: false,
+ protected: false,
+ defaultValue: '',
+ multiple: false,
+ suffix: '',
+ prefix: '',
+ placeholder: '',
+ key: 'h',
+ label: 'H',
+ inputMask: '',
+ inputType: 'text',
+ tableView: true,
+ input: true,
+ },
+ {
+ type: 'textfield',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ validate: {
+ customPrivate: false,
+ custom: '',
+ pattern: '',
+ maxLength: '',
+ minLength: '',
+ required: false,
+ },
+ persistent: true,
+ unique: false,
+ protected: false,
+ defaultValue: '',
+ multiple: false,
+ suffix: '',
+ prefix: '',
+ placeholder: '',
+ key: 'i',
+ label: 'I',
+ inputMask: '',
+ inputType: 'text',
+ tableView: true,
+ input: true,
+ },
+ ],
+ tree: true,
+ input: true,
+ },
+ ],
+ },
+ {
+ components: [
+ {
+ type: 'textfield',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ validate: {
+ customPrivate: false,
+ custom: '',
+ pattern: '',
+ maxLength: '',
+ minLength: '',
+ required: false,
+ },
+ persistent: true,
+ unique: false,
+ protected: false,
+ defaultValue: '',
+ multiple: false,
+ suffix: '',
+ prefix: '',
+ placeholder: '',
+ key: 'e',
+ label: 'E',
+ inputMask: '',
+ inputType: 'text',
+ tableView: true,
+ input: true,
+ },
+ ],
+ },
+ ],
+ input: false,
+ },
+ {
+ type: 'textfield',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ validate: {
+ customPrivate: false,
+ custom: '',
+ pattern: '',
+ maxLength: '',
+ minLength: '',
+ required: false,
+ },
+ persistent: true,
+ unique: false,
+ protected: false,
+ defaultValue: '',
+ multiple: false,
+ suffix: '',
+ prefix: '',
+ placeholder: '',
+ key: 'j',
+ label: 'J',
+ inputMask: '',
+ inputType: 'text',
+ tableView: true,
+ input: true,
+ },
+ ],
+ legend: 'B',
+ tableView: true,
+ input: false,
+ },
+ {
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ type: 'datagrid',
+ persistent: true,
+ protected: false,
+ key: 'k',
+ label: 'K',
+ tableView: true,
+ components: [
+ {
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ hideLabel: true,
+ type: 'container',
+ persistent: true,
+ protected: false,
+ key: 'n',
+ label: 'N',
+ tableView: true,
+ components: [
+ {
+ type: 'textfield',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ validate: {
+ customPrivate: false,
+ custom: '',
+ pattern: '',
+ maxLength: '',
+ minLength: '',
+ required: false,
+ },
+ persistent: true,
+ unique: false,
+ protected: false,
+ defaultValue: '',
+ multiple: false,
+ suffix: '',
+ prefix: '',
+ placeholder: '',
+ key: 'o',
+ label: 'O',
+ inputMask: '',
+ inputType: 'text',
+ tableView: true,
+ input: true,
+ },
+ {
+ type: 'textfield',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ validate: {
+ customPrivate: false,
+ custom: '',
+ pattern: '',
+ maxLength: '',
+ minLength: '',
+ required: false,
+ },
+ persistent: true,
+ unique: false,
+ protected: false,
+ defaultValue: '',
+ multiple: false,
+ suffix: '',
+ prefix: '',
+ placeholder: '',
+ key: 'p',
+ label: 'P',
+ inputMask: '',
+ inputType: 'text',
+ tableView: true,
+ input: true,
+ },
+ {
+ type: 'textfield',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ validate: {
+ customPrivate: false,
+ custom: '',
+ pattern: '',
+ maxLength: '',
+ minLength: '',
+ required: false,
+ },
+ persistent: true,
+ unique: false,
+ protected: false,
+ defaultValue: '',
+ multiple: false,
+ suffix: '',
+ prefix: '',
+ placeholder: '',
+ key: 'q',
+ label: 'Q',
+ inputMask: '',
+ inputType: 'text',
+ tableView: true,
+ input: true,
+ },
+ ],
+ tree: true,
+ input: true,
+ },
+ {
+ hideLabel: true,
+ type: 'textfield',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ validate: {
+ customPrivate: false,
+ custom: '',
+ pattern: '',
+ maxLength: '',
+ minLength: '',
+ required: false,
+ },
+ persistent: true,
+ unique: false,
+ protected: false,
+ defaultValue: '',
+ multiple: false,
+ suffix: '',
+ prefix: '',
+ placeholder: '',
+ key: 'm',
+ label: 'M',
+ inputMask: '',
+ inputType: 'text',
+ tableView: true,
+ input: true,
+ },
+ {
+ hideLabel: true,
+ type: 'textfield',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ validate: {
+ customPrivate: false,
+ custom: '',
+ pattern: '',
+ maxLength: '',
+ minLength: '',
+ required: false,
+ },
+ persistent: true,
+ unique: false,
+ protected: false,
+ defaultValue: '',
+ multiple: false,
+ suffix: '',
+ prefix: '',
+ placeholder: '',
+ key: 'l',
+ label: 'L',
+ inputMask: '',
+ inputType: 'text',
+ tableView: true,
+ input: true,
+ },
+ ],
+ tree: true,
+ input: true,
+ },
+ {
+ type: 'textfield',
+ conditional: {
+ eq: '',
+ when: null,
+ show: null,
+ },
+ validate: {
+ customPrivate: false,
+ custom: '',
+ pattern: '',
+ maxLength: '',
+ minLength: '',
+ required: false,
+ },
+ persistent: true,
+ unique: false,
+ protected: false,
+ defaultValue: '',
+ multiple: false,
+ suffix: '',
+ prefix: '',
+ placeholder: '',
+ key: 'r',
+ label: 'R',
+ inputMask: '',
+ inputType: 'text',
+ tableView: true,
+ input: true,
+ },
+ {
+ type: 'button',
+ theme: 'primary',
+ disableOnInvalid: true,
+ action: 'submit',
+ block: false,
+ rightIcon: '',
+ leftIcon: '',
+ size: 'md',
+ key: 'submit',
+ tableView: false,
+ label: 'Submit',
+ input: true,
+ },
+ {
+ label: 'Tagpad',
+ tableView: false,
+ key: 'tagpad',
+ type: 'tagpad',
+ input: true,
+ components: [
+ {
+ label: 'Text Field',
+ tableView: true,
+ key: 'a',
+ type: 'textfield',
+ input: true,
+ },
+ ],
+ },
+ ];
+ const components3 = [
+ {
+ label: 'HTML',
+ tag: 'p',
+ content: '',
+ key: 'html',
+ type: 'htmlelement',
+ input: false,
+ },
+ {
+ html: 'some text
',
+ label: 'Content',
+ key: 'content',
+ type: 'content',
+ input: false,
+ },
+ {
+ label: 'Text Field',
+ key: 'textField',
+ type: 'textfield',
+ input: true,
+ },
+ {
+ label: 'Number',
+ key: 'number',
+ type: 'number',
+ input: true,
+ },
+ ];
+
+ it('should iterate through nested components in the right order', function () {
+ let n = 1;
+ eachComponent(components, (component: Component) => {
+ expect((component as any).order).to.equal(n);
+ n += 1;
+ });
+ });
+
+ it('should include layouts components if provided', function () {
+ let numComps = 0;
+ let numLayout = 0;
+ eachComponent(
+ components,
+ (component: Component) => {
+ if (isLayoutComponent(component)) {
+ numLayout++;
+ } else {
+ numComps++;
+ }
+ },
+ true,
+ );
+ expect(numLayout).to.be.equal(3);
+ expect(numComps).to.be.equal(8);
+ });
+
+ it('Should provide the paths to all of the components', function () {
+ const paths = [
+ 'one',
+ 'parent1',
+ 'two',
+ 'parent2',
+ 'three',
+ '',
+ 'four',
+ 'five',
+ 'six',
+ 'seven',
+ 'eight',
+ ];
+ const testPaths: string[] = [];
+ eachComponent(
+ components,
+ (component: Component, path: string) => {
+ testPaths.push(path);
+ },
+ true,
+ );
+ expect(paths).to.deep.equal(testPaths);
+ });
+
+ it('Should iterate over each component given a flat components array', function () {
+ const components = [
+ {
+ type: 'textfield',
+ key: 'textField',
+ input: true,
+ },
+ {
+ type: 'textarea',
+ key: 'textArea',
+ input: true,
+ },
+ ];
+ const rowResults: Map = new Map();
+ eachComponent(components, (component: Component, path: string) => {
+ rowResults.set(path, component);
+ });
+ expect(rowResults.size).to.equal(2);
+ expect(rowResults.get('textField')).to.deep.equal({
+ type: 'textfield',
+ key: 'textField',
+ input: true,
+ });
+ expect(rowResults.get('textArea')).to.deep.equal({
+ type: 'textarea',
+ key: 'textArea',
+ input: true,
+ });
+ });
+
+ it('Should iterate over each component with correct pathing given a container component', function () {
+ const components = [
+ {
+ type: 'textfield',
+ key: 'textField',
+ input: true,
+ },
+ {
+ type: 'container',
+ key: 'container',
+ input: true,
+ components: [
+ {
+ type: 'textfield',
+ key: 'nestedTextField',
+ input: true,
+ },
+ {
+ type: 'textarea',
+ key: 'nestedTextArea',
+ input: true,
+ },
+ ],
+ },
+ ];
+ const rowResults: Map = new Map();
+ eachComponent(
+ components,
+ (component: Component, path: string) => {
+ rowResults.set(path, component);
+ },
+ true,
+ );
+ expect(rowResults.size).to.equal(4);
+ expect(rowResults.get('textField')).to.deep.equal({
+ type: 'textfield',
+ key: 'textField',
+ input: true,
+ });
+ expect(rowResults.get('container')).to.deep.equal({
+ type: 'container',
+ key: 'container',
+ input: true,
+ components: [
+ {
+ type: 'textfield',
+ key: 'nestedTextField',
+ input: true,
+ },
+ {
+ type: 'textarea',
+ key: 'nestedTextArea',
+ input: true,
+ },
+ ],
+ });
+ expect(rowResults.get('container.nestedTextField')).to.deep.equal({
+ type: 'textfield',
+ key: 'nestedTextField',
+ input: true,
+ });
+ expect(rowResults.get('container.nestedTextArea')).to.deep.equal({
+ type: 'textarea',
+ key: 'nestedTextArea',
+ input: true,
+ });
+ });
+
+ it('Should iterate over each component with correct pathing given a datagrid component', function () {
+ const components = [
+ {
+ type: 'textfield',
+ key: 'textField',
+ input: true,
+ },
+ {
+ type: 'datagrid',
+ key: 'dataGrid',
+ input: true,
+ components: [
+ {
+ type: 'textfield',
+ key: 'nestedTextField',
+ input: true,
+ },
+ {
+ type: 'textarea',
+ key: 'nestedTextArea',
+ input: true,
+ },
+ ],
+ },
+ ];
+ const rowResults: Map = new Map();
+ eachComponent(
+ components,
+ (component: Component, path: string) => {
+ rowResults.set(path, component);
+ },
+ true,
+ );
+ expect(rowResults.size).to.equal(4);
+ expect(rowResults.get('textField')).to.deep.equal({
+ type: 'textfield',
+ key: 'textField',
+ input: true,
+ });
+ expect(rowResults.get('dataGrid')).to.deep.equal({
+ type: 'datagrid',
+ key: 'dataGrid',
+ input: true,
+ components: [
+ {
+ type: 'textfield',
+ key: 'nestedTextField',
+ input: true,
+ },
+ {
+ type: 'textarea',
+ key: 'nestedTextArea',
+ input: true,
+ },
+ ],
+ });
+ expect(rowResults.get('dataGrid.nestedTextField')).to.deep.equal({
+ type: 'textfield',
+ key: 'nestedTextField',
+ input: true,
+ });
+ expect(rowResults.get('dataGrid.nestedTextArea')).to.deep.equal({
+ type: 'textarea',
+ key: 'nestedTextArea',
+ input: true,
+ });
+ });
+
+ it("Should iterate over each component with correct pathing given a datagrid's child components", function () {
+ const components = [
+ {
+ type: 'datagrid',
+ key: 'dataGrid',
+ input: true,
+ components: [
+ {
+ type: 'textfield',
+ key: 'nestedTextField',
+ input: true,
+ },
+ {
+ type: 'textarea',
+ key: 'nestedTextArea',
+ input: true,
+ },
+ ],
+ },
+ ];
+ const rowResults: Map = new Map();
+ eachComponent(
+ components[0].components,
+ (component: Component, path: string) => {
+ rowResults.set(path, component);
+ },
+ true,
+ 'dataGrid',
+ );
+ expect(rowResults.size).to.equal(2);
+ expect(rowResults.get('dataGrid.nestedTextField')).to.deep.equal({
+ type: 'textfield',
+ key: 'nestedTextField',
+ input: true,
+ });
+ expect(rowResults.get('dataGrid.nestedTextArea')).to.deep.equal({
+ type: 'textarea',
+ key: 'nestedTextArea',
+ input: true,
+ });
+ });
+
+ it('Should be able to generate paths based on component types', function () {
+ const paths = [
+ 'a',
+ 'b',
+ 'c',
+ 'd',
+ 'f',
+ 'f.g',
+ 'f.h',
+ 'f.i',
+ 'e',
+ 'j',
+ 'k',
+ 'k.n',
+ 'k.n.o',
+ 'k.n.p',
+ 'k.n.q',
+ 'k.m',
+ 'k.l',
+ 'r',
+ 'submit',
+ 'tagpad',
+ 'tagpad.a',
+ ];
+ const testPaths: string[] = [];
+ eachComponent(
+ components2,
+ (component: Component, path: string) => {
+ testPaths.push(path);
+ },
+ true,
+ );
+ expect(paths).to.deep.equal(testPaths);
+ });
+
+ it('Should still provide the correct paths when it is not recursive', function () {
+ const paths = [
+ 'a',
+ 'd',
+ 'f',
+ 'f.g',
+ 'f.h',
+ 'f.i',
+ 'e',
+ 'j',
+ 'k',
+ 'k.n',
+ 'k.n.o',
+ 'k.n.p',
+ 'k.n.q',
+ 'k.m',
+ 'k.l',
+ 'r',
+ 'submit',
+ 'tagpad',
+ 'tagpad.a',
+ ];
+ const testPaths: string[] = [];
+ eachComponent(components2, (component: Component, path: string) => {
+ testPaths.push(path);
+ });
+ expect(paths).to.deep.equal(testPaths);
+ });
+
+ it('should be able to block recursion', function () {
+ let numComps = 0;
+ let numLayout = 0;
+ eachComponent(
+ components,
+ (component: Component) => {
+ if (isLayoutComponent(component)) {
+ numLayout++;
+ } else {
+ numComps++;
+ }
+
+ if (component.type === 'table') {
+ let numInTable = 0;
+ const tableComponent: TableComponent = component as TableComponent;
+ tableComponent.rows.forEach((row: Component[]) => {
+ row.forEach((comp: Component) => {
+ eachComponent((comp as HasChildComponents).components, () => {
+ numInTable++;
+ });
+ });
+ });
+ expect(numInTable).to.be.equal(4);
+ return true;
+ }
+ },
+ true,
+ );
+ expect(numLayout).to.be.equal(3);
+ expect(numComps).to.be.equal(4);
+ });
+
+ it('should not include `htmlelement` components when `includeAll` is not provided', function () {
+ let htmlComponentsAmount = 0;
+ eachComponent(components3, (component: Component) => {
+ if (component.type === 'htmlelement') {
+ htmlComponentsAmount++;
+ }
+ });
+ expect(htmlComponentsAmount).to.be.equal(0);
+ });
+
+ it('should include `htmlelement` components when `includeAll` is provided', function () {
+ let htmlComponentsAmount = 0;
+ eachComponent(
+ components3,
+ (component: Component) => {
+ if (component.type === 'htmlelement') {
+ htmlComponentsAmount++;
+ }
+ },
+ true,
+ );
+ expect(htmlComponentsAmount).to.be.equal(1);
+ });
+
+ it('should not include `content` components when `includeAll` is not provided', function () {
+ let contentComponentsAmount = 0;
+ eachComponent(components3, (component: Component) => {
+ if (component.type === 'content') {
+ contentComponentsAmount++;
+ }
+ });
+ expect(contentComponentsAmount).to.be.equal(0);
+ });
+
+ it('should include `content` components when `includeAll` is provided', function () {
+ let contentComponentsAmount = 0;
+ eachComponent(
+ components3,
+ (component: Component) => {
+ if (component.type === 'content') {
+ contentComponentsAmount++;
+ }
+ },
+ true,
+ );
+ expect(contentComponentsAmount).to.be.equal(1);
+ });
+
+ it('should not mutate the path property if contained in component', function () {
+ const components = [
+ {
+ type: 'textfield',
+ key: 'textField',
+ input: true,
+ path: 'doNotMutate',
+ },
+ {
+ type: 'container',
+ key: 'container',
+ input: true,
+ path: 'doNotMutate',
+ components: [
+ {
+ type: 'textfield',
+ key: 'nestedTextField',
+ path: 'doNotMutate',
+ input: true,
+ },
+ {
+ type: 'textarea',
+ key: 'nestedTextArea',
+ path: 'doNotMutate',
+ input: true,
+ },
+ ],
+ },
+ ];
+ eachComponent(
+ components,
+ (component: Component, path: string) => {
+ if (component.key === 'textField') {
+ expect(component.path).to.equal('doNotMutate');
+ expect(path).to.equal('textField');
+ }
+ if (component.key === 'container') {
+ expect(component.path).to.equal('doNotMutate');
+ expect(path).to.equal('container');
+ }
+ if (component.key === 'nestedTextField') {
+ expect(component.path).to.equal('doNotMutate');
+ expect(path).to.equal('container.nestedTextField');
+ }
+ if (component.key === 'nestedTextArea') {
+ expect(component.path).to.equal('doNotMutate');
+ expect(path).to.equal('container.nestedTextArea');
+ }
+ },
+ true,
+ );
+ });
+});
diff --git a/src/utils/formUtil/eachComponent.ts b/src/utils/formUtil/eachComponent.ts
index 9f9dc050..3034149f 100644
--- a/src/utils/formUtil/eachComponent.ts
+++ b/src/utils/formUtil/eachComponent.ts
@@ -14,8 +14,6 @@ import { componentInfo, componentPath, componentFormPath } from './index';
* The current data path of the element. Example: data.user.firstName
* @param {Object} parent
* The parent object.
- * @param {Boolean} noComponentChange
- * Whether or not to add properties (e.g. path/parent) to the component object
*/
export function eachComponent(
components: Component[],
@@ -23,7 +21,6 @@ export function eachComponent(
includeAll?: boolean,
path: string = '',
parent?: Component,
- noComponentChange?: boolean,
) {
if (!components) return;
components.forEach((component: any) => {
@@ -33,7 +30,7 @@ export function eachComponent(
const info = componentInfo(component);
let noRecurse = false;
// Keep track of parent references.
- if (parent && !noComponentChange) {
+ if (parent) {
// Ensure we don't create infinite JSON structures.
Object.defineProperty(component, 'parent', {
enumerable: false,
@@ -58,14 +55,6 @@ export function eachComponent(
const compPath = componentPath(component, path);
- if (!noComponentChange) {
- Object.defineProperty(component, 'path', {
- enumerable: false,
- writable: true,
- value: compPath,
- });
- }
-
if (includeAll || component.tree || !info.layout) {
noRecurse = !!fn(component, compPath, components, parent);
}
@@ -73,27 +62,13 @@ export function eachComponent(
if (!noRecurse) {
if (info.hasColumns) {
component.columns.forEach((column: any) =>
- eachComponent(
- column.components,
- fn,
- includeAll,
- path,
- parent ? component : null,
- noComponentChange,
- ),
+ eachComponent(column.components, fn, includeAll, path, parent ? component : null),
);
} else if (info.hasRows) {
component.rows.forEach((row: any) => {
if (Array.isArray(row)) {
row.forEach((column) =>
- eachComponent(
- column.components,
- fn,
- includeAll,
- path,
- parent ? component : null,
- noComponentChange,
- ),
+ eachComponent(column.components, fn, includeAll, path, parent ? component : null),
);
}
});
@@ -104,7 +79,6 @@ export function eachComponent(
includeAll,
componentFormPath(component, path, compPath),
parent ? component : null,
- noComponentChange,
);
}
}
diff --git a/src/utils/formUtil/eachComponentAsync.ts b/src/utils/formUtil/eachComponentAsync.ts
index deee2143..36985a32 100644
--- a/src/utils/formUtil/eachComponentAsync.ts
+++ b/src/utils/formUtil/eachComponentAsync.ts
@@ -7,7 +7,6 @@ export async function eachComponentAsync(
includeAll = false,
path = '',
parent?: any,
- noComponentChange?: boolean,
) {
if (!components) return;
for (let i = 0; i < components.length; i++) {
@@ -17,7 +16,7 @@ export async function eachComponentAsync(
const component = components[i];
const info = componentInfo(component);
// Keep track of parent references.
- if (parent && !noComponentChange) {
+ if (parent) {
// Ensure we don't create infinite JSON structures.
Object.defineProperty(component, 'parent', {
enumerable: false,
@@ -41,13 +40,6 @@ export async function eachComponentAsync(
}
const compPath = componentPath(component, path);
- if (!noComponentChange) {
- Object.defineProperty(component, 'path', {
- enumerable: false,
- writable: true,
- value: compPath,
- });
- }
if (includeAll || component.tree || !info.layout) {
if (await fn(component, compPath, components, parent)) {
continue;
@@ -61,7 +53,6 @@ export async function eachComponentAsync(
includeAll,
path,
parent ? component : null,
- noComponentChange,
);
}
} else if (info.hasRows) {
@@ -75,7 +66,6 @@ export async function eachComponentAsync(
includeAll,
path,
parent ? component : null,
- noComponentChange,
);
}
}
@@ -87,7 +77,6 @@ export async function eachComponentAsync(
includeAll,
componentFormPath(component, path, compPath),
parent ? component : null,
- noComponentChange,
);
}
}
diff --git a/src/utils/formUtil/index.ts b/src/utils/formUtil/index.ts
index 318759d7..0350a54f 100644
--- a/src/utils/formUtil/index.ts
+++ b/src/utils/formUtil/index.ts
@@ -431,9 +431,6 @@ export function getComponent(
}
},
includeAll,
- undefined,
- undefined,
- true,
);
return result;
}