diff --git a/.eslintcache b/.eslintcache new file mode 100644 index 00000000..205ac73f --- /dev/null +++ b/.eslintcache @@ -0,0 +1 @@ +[{"/Users/brendanjbond/Projects/formio/core/src/process/validation/__tests__/Validator.test.ts":"1","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateTime.test.ts":"2","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateTime.ts":"3","/Users/brendanjbond/Projects/formio/core/src/ejs.d.ts":"4","/Users/brendanjbond/Projects/formio/core/src/error/FieldError.ts":"5","/Users/brendanjbond/Projects/formio/core/src/error/ProcessorError.ts":"6","/Users/brendanjbond/Projects/formio/core/src/error/index.ts":"7","/Users/brendanjbond/Projects/formio/core/src/index.ts":"8","/Users/brendanjbond/Projects/formio/core/src/modules/index.ts":"9","/Users/brendanjbond/Projects/formio/core/src/modules/jsonlogic/__tests__/operators.test.ts":"10","/Users/brendanjbond/Projects/formio/core/src/modules/jsonlogic/index.ts":"11","/Users/brendanjbond/Projects/formio/core/src/modules/jsonlogic/jsonLogic.ts":"12","/Users/brendanjbond/Projects/formio/core/src/modules/jsonlogic/operators.ts":"13","/Users/brendanjbond/Projects/formio/core/src/process/__tests__/fixtures/index.ts":"14","/Users/brendanjbond/Projects/formio/core/src/process/__tests__/fixtures/util.ts":"15","/Users/brendanjbond/Projects/formio/core/src/process/__tests__/process.test.ts":"16","/Users/brendanjbond/Projects/formio/core/src/process/calculation/__tests__/calculation.test.ts":"17","/Users/brendanjbond/Projects/formio/core/src/process/calculation/index.ts":"18","/Users/brendanjbond/Projects/formio/core/src/process/clearHidden.ts":"19","/Users/brendanjbond/Projects/formio/core/src/process/conditions/__tests__/conditions.test.ts":"20","/Users/brendanjbond/Projects/formio/core/src/process/conditions/index.ts":"21","/Users/brendanjbond/Projects/formio/core/src/process/defaultValue/__tests__/defaultValue.test.ts":"22","/Users/brendanjbond/Projects/formio/core/src/process/defaultValue/index.ts":"23","/Users/brendanjbond/Projects/formio/core/src/process/dereference/index.ts":"24","/Users/brendanjbond/Projects/formio/core/src/process/fetch/__tests__/fetch.test.ts":"25","/Users/brendanjbond/Projects/formio/core/src/process/fetch/index.ts":"26","/Users/brendanjbond/Projects/formio/core/src/process/filter/__tests__/filter.test.ts":"27","/Users/brendanjbond/Projects/formio/core/src/process/filter/index.ts":"28","/Users/brendanjbond/Projects/formio/core/src/process/hideChildren.ts":"29","/Users/brendanjbond/Projects/formio/core/src/process/index.ts":"30","/Users/brendanjbond/Projects/formio/core/src/process/logic/index.ts":"31","/Users/brendanjbond/Projects/formio/core/src/process/normalize/__tests__/normalize.test.ts":"32","/Users/brendanjbond/Projects/formio/core/src/process/normalize/index.ts":"33","/Users/brendanjbond/Projects/formio/core/src/process/populate/__tests__/populate.test.ts":"34","/Users/brendanjbond/Projects/formio/core/src/process/populate/index.ts":"35","/Users/brendanjbond/Projects/formio/core/src/process/process.ts":"36","/Users/brendanjbond/Projects/formio/core/src/process/processOne.ts":"37","/Users/brendanjbond/Projects/formio/core/src/process/validation/__tests__/fixtures/components.ts":"38","/Users/brendanjbond/Projects/formio/core/src/process/validation/__tests__/fixtures/forms.ts":"39","/Users/brendanjbond/Projects/formio/core/src/process/validation/__tests__/multiple.test.ts":"40","/Users/brendanjbond/Projects/formio/core/src/process/validation/__tests__/util.test.ts":"41","/Users/brendanjbond/Projects/formio/core/src/process/validation/i18n/en.ts":"42","/Users/brendanjbond/Projects/formio/core/src/process/validation/i18n/index.ts":"43","/Users/brendanjbond/Projects/formio/core/src/process/validation/index.ts":"44","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/fixtures/components.ts":"45","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/fixtures/forms.ts":"46","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/fixtures/util.ts":"47","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateAvailableItems.test.ts":"48","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateCustom.test.ts":"49","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateDate.test.ts":"50","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateDay.test.ts":"51","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateEmail.test.ts":"52","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateJson.test.ts":"53","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMask.test.ts":"54","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMaximumDay.test.ts":"55","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMaximumLength.test.ts":"56","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMaximumSelectedCount.test.ts":"57","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMaximumValue.test.ts":"58","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMaximumWords.test.ts":"59","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMaximumYear.test.ts":"60","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMinimumDay.test.ts":"61","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMinimumLength.test.ts":"62","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMinimumSelectedCount.test.ts":"63","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMinimumValue.test.ts":"64","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMinimumWords.test.ts":"65","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMinimumYear.test.ts":"66","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMultiple.test.ts":"67","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateNumber.test.ts":"68","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateRegexPattern.test.ts":"69","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateRequired.test.ts":"70","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateRequiredDay.test.ts":"71","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateUrl.test.ts":"72","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateUrlSelectValue.test.ts":"73","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/asynchronousRules.ts":"74","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/clientRules.ts":"75","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/databaseRules.ts":"76","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/evaluationRules.ts":"77","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/index.ts":"78","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateAvailableItems.ts":"79","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateCustom.ts":"80","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateDate.ts":"81","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateDay.ts":"82","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateEmail.ts":"83","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateJson.ts":"84","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMask.ts":"85","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMaximumDay.ts":"86","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMaximumLength.ts":"87","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMaximumSelectedCount.ts":"88","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMaximumValue.ts":"89","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMaximumWords.ts":"90","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMaximumYear.ts":"91","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMinimumDay.ts":"92","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMinimumLength.ts":"93","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMinimumSelectedCount.ts":"94","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMinimumValue.ts":"95","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMinimumWords.ts":"96","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMinimumYear.ts":"97","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMultiple.ts":"98","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateNumber.ts":"99","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateRegexPattern.ts":"100","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateRequired.ts":"101","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateRequiredDay.ts":"102","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateRequiredSurvey.ts":"103","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateResourceSelectValue.ts":"104","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateUnique.ts":"105","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateUrl.ts":"106","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateUrlSelectValue.ts":"107","/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateValueProperty.ts":"108","/Users/brendanjbond/Projects/formio/core/src/process/validation/util.ts":"109","/Users/brendanjbond/Projects/formio/core/src/process/validation/validate.ts":"110","/Users/brendanjbond/Projects/formio/core/src/sdk/Formio.ts":"111","/Users/brendanjbond/Projects/formio/core/src/sdk/Plugins.ts":"112","/Users/brendanjbond/Projects/formio/core/src/sdk/__tests__/Formio.test.ts":"113","/Users/brendanjbond/Projects/formio/core/src/sdk/index.ts":"114","/Users/brendanjbond/Projects/formio/core/src/types/Access.ts":"115","/Users/brendanjbond/Projects/formio/core/src/types/Action.ts":"116","/Users/brendanjbond/Projects/formio/core/src/types/AdvancedLogic.ts":"117","/Users/brendanjbond/Projects/formio/core/src/types/BaseComponent.ts":"118","/Users/brendanjbond/Projects/formio/core/src/types/Component.ts":"119","/Users/brendanjbond/Projects/formio/core/src/types/DataObject.ts":"120","/Users/brendanjbond/Projects/formio/core/src/types/Form.ts":"121","/Users/brendanjbond/Projects/formio/core/src/types/PassedComponentInstance.ts":"122","/Users/brendanjbond/Projects/formio/core/src/types/Role.ts":"123","/Users/brendanjbond/Projects/formio/core/src/types/RuleFn.ts":"124","/Users/brendanjbond/Projects/formio/core/src/types/Submission.ts":"125","/Users/brendanjbond/Projects/formio/core/src/types/formUtil.ts":"126","/Users/brendanjbond/Projects/formio/core/src/types/index.ts":"127","/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessConfig.ts":"128","/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessContext.ts":"129","/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessType.ts":"130","/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessorContext.ts":"131","/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessorFn.ts":"132","/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessorInfo.ts":"133","/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessorScope.ts":"134","/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessorType.ts":"135","/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessorsScope.ts":"136","/Users/brendanjbond/Projects/formio/core/src/types/process/calculation/CalculationContext.ts":"137","/Users/brendanjbond/Projects/formio/core/src/types/process/calculation/CalculationScope.ts":"138","/Users/brendanjbond/Projects/formio/core/src/types/process/calculation/index.ts":"139","/Users/brendanjbond/Projects/formio/core/src/types/process/conditions/ConditionsContext.ts":"140","/Users/brendanjbond/Projects/formio/core/src/types/process/conditions/ConditionsScope.ts":"141","/Users/brendanjbond/Projects/formio/core/src/types/process/conditions/index.ts":"142","/Users/brendanjbond/Projects/formio/core/src/types/process/defaultValue/DefaultValueContext.ts":"143","/Users/brendanjbond/Projects/formio/core/src/types/process/defaultValue/DefaultValueScope.ts":"144","/Users/brendanjbond/Projects/formio/core/src/types/process/defaultValue/index.ts":"145","/Users/brendanjbond/Projects/formio/core/src/types/process/fetch/FetchContext.ts":"146","/Users/brendanjbond/Projects/formio/core/src/types/process/fetch/FetchScope.ts":"147","/Users/brendanjbond/Projects/formio/core/src/types/process/fetch/index.ts":"148","/Users/brendanjbond/Projects/formio/core/src/types/process/filter/FilterContext.ts":"149","/Users/brendanjbond/Projects/formio/core/src/types/process/filter/FilterScope.ts":"150","/Users/brendanjbond/Projects/formio/core/src/types/process/filter/index.ts":"151","/Users/brendanjbond/Projects/formio/core/src/types/process/index.ts":"152","/Users/brendanjbond/Projects/formio/core/src/types/process/logic/LogicContext.ts":"153","/Users/brendanjbond/Projects/formio/core/src/types/process/logic/LogicScope.ts":"154","/Users/brendanjbond/Projects/formio/core/src/types/process/logic/index.ts":"155","/Users/brendanjbond/Projects/formio/core/src/types/process/populate/PopulateContext.ts":"156","/Users/brendanjbond/Projects/formio/core/src/types/process/populate/PopulateScope.ts":"157","/Users/brendanjbond/Projects/formio/core/src/types/process/populate/index.ts":"158","/Users/brendanjbond/Projects/formio/core/src/types/process/validation/ValidationContext.ts":"159","/Users/brendanjbond/Projects/formio/core/src/types/process/validation/ValidationFn.ts":"160","/Users/brendanjbond/Projects/formio/core/src/types/process/validation/ValidationRuleInfo.ts":"161","/Users/brendanjbond/Projects/formio/core/src/types/process/validation/ValidationScope.ts":"162","/Users/brendanjbond/Projects/formio/core/src/types/process/validation/index.ts":"163","/Users/brendanjbond/Projects/formio/core/src/types/project/Project.ts":"164","/Users/brendanjbond/Projects/formio/core/src/types/project/index.ts":"165","/Users/brendanjbond/Projects/formio/core/src/types/project/settings/ProjectSettings.ts":"166","/Users/brendanjbond/Projects/formio/core/src/types/project/settings/authorization/index.ts":"167","/Users/brendanjbond/Projects/formio/core/src/types/project/settings/authorization/ldap.ts":"168","/Users/brendanjbond/Projects/formio/core/src/types/project/settings/authorization/oauth.ts":"169","/Users/brendanjbond/Projects/formio/core/src/types/project/settings/authorization/saml.ts":"170","/Users/brendanjbond/Projects/formio/core/src/types/project/settings/index.ts":"171","/Users/brendanjbond/Projects/formio/core/src/types/project/settings/integrations/captcha.ts":"172","/Users/brendanjbond/Projects/formio/core/src/types/project/settings/integrations/dataConnections.ts":"173","/Users/brendanjbond/Projects/formio/core/src/types/project/settings/integrations/eSign.ts":"174","/Users/brendanjbond/Projects/formio/core/src/types/project/settings/integrations/email.ts":"175","/Users/brendanjbond/Projects/formio/core/src/types/project/settings/integrations/fileStorage.ts":"176","/Users/brendanjbond/Projects/formio/core/src/types/project/settings/integrations/index.ts":"177","/Users/brendanjbond/Projects/formio/core/src/utils/Database.ts":"178","/Users/brendanjbond/Projects/formio/core/src/utils/Evaluator.ts":"179","/Users/brendanjbond/Projects/formio/core/src/utils/__tests__/Evaluator.test.ts":"180","/Users/brendanjbond/Projects/formio/core/src/utils/__tests__/date.test.ts":"181","/Users/brendanjbond/Projects/formio/core/src/utils/__tests__/formUtil.test.ts":"182","/Users/brendanjbond/Projects/formio/core/src/utils/__tests__/jwtDecode.test.ts":"183","/Users/brendanjbond/Projects/formio/core/src/utils/__tests__/unwind.test.ts":"184","/Users/brendanjbond/Projects/formio/core/src/utils/conditions.ts":"185","/Users/brendanjbond/Projects/formio/core/src/utils/date.ts":"186","/Users/brendanjbond/Projects/formio/core/src/utils/dom.ts":"187","/Users/brendanjbond/Projects/formio/core/src/utils/error.ts":"188","/Users/brendanjbond/Projects/formio/core/src/utils/fastCloneDeep.ts":"189","/Users/brendanjbond/Projects/formio/core/src/utils/formUtil/eachComponent.ts":"190","/Users/brendanjbond/Projects/formio/core/src/utils/formUtil/eachComponentAsync.ts":"191","/Users/brendanjbond/Projects/formio/core/src/utils/formUtil/eachComponentData.ts":"192","/Users/brendanjbond/Projects/formio/core/src/utils/formUtil/eachComponentDataAsync.ts":"193","/Users/brendanjbond/Projects/formio/core/src/utils/formUtil/index.ts":"194","/Users/brendanjbond/Projects/formio/core/src/utils/index.ts":"195","/Users/brendanjbond/Projects/formio/core/src/utils/jwtDecode.ts":"196","/Users/brendanjbond/Projects/formio/core/src/utils/logic.ts":"197","/Users/brendanjbond/Projects/formio/core/src/utils/mask.ts":"198","/Users/brendanjbond/Projects/formio/core/src/utils/operators/ConditionOperator.js":"199","/Users/brendanjbond/Projects/formio/core/src/utils/operators/DateGreaterThan.js":"200","/Users/brendanjbond/Projects/formio/core/src/utils/operators/DateGreaterThanOrEqual.js":"201","/Users/brendanjbond/Projects/formio/core/src/utils/operators/DateLessThan.js":"202","/Users/brendanjbond/Projects/formio/core/src/utils/operators/DateLessThanOrEqual.js":"203","/Users/brendanjbond/Projects/formio/core/src/utils/operators/EndsWith.js":"204","/Users/brendanjbond/Projects/formio/core/src/utils/operators/GreaterThan.js":"205","/Users/brendanjbond/Projects/formio/core/src/utils/operators/GreaterThanOrEqual.js":"206","/Users/brendanjbond/Projects/formio/core/src/utils/operators/Includes.js":"207","/Users/brendanjbond/Projects/formio/core/src/utils/operators/IsDateEqual.js":"208","/Users/brendanjbond/Projects/formio/core/src/utils/operators/IsEmptyValue.js":"209","/Users/brendanjbond/Projects/formio/core/src/utils/operators/IsEqualTo.js":"210","/Users/brendanjbond/Projects/formio/core/src/utils/operators/IsNotDateEqual.js":"211","/Users/brendanjbond/Projects/formio/core/src/utils/operators/IsNotEmptyValue.js":"212","/Users/brendanjbond/Projects/formio/core/src/utils/operators/IsNotEqualTo.js":"213","/Users/brendanjbond/Projects/formio/core/src/utils/operators/LessThan.js":"214","/Users/brendanjbond/Projects/formio/core/src/utils/operators/LessThanOrEqual.js":"215","/Users/brendanjbond/Projects/formio/core/src/utils/operators/NotIncludes.js":"216","/Users/brendanjbond/Projects/formio/core/src/utils/operators/StartsWith.js":"217","/Users/brendanjbond/Projects/formio/core/src/utils/operators/index.js":"218","/Users/brendanjbond/Projects/formio/core/src/utils/override.ts":"219","/Users/brendanjbond/Projects/formio/core/src/utils/sanitize.ts":"220","/Users/brendanjbond/Projects/formio/core/src/utils/unwind.ts":"221","/Users/brendanjbond/Projects/formio/core/src/utils/utils.ts":"222"},{"size":1604,"mtime":1729093374186,"results":"223","hashOfConfig":"224"},{"size":1843,"mtime":1729093463214,"results":"225","hashOfConfig":"224"},{"size":1664,"mtime":1729093448221,"results":"226","hashOfConfig":"224"},{"size":74,"mtime":1729092985454,"results":"227","hashOfConfig":"224"},{"size":1680,"mtime":1729092985455,"results":"228","hashOfConfig":"224"},{"size":429,"mtime":1729092985455,"results":"229","hashOfConfig":"224"},{"size":64,"mtime":1713537140904,"results":"230","hashOfConfig":"224"},{"size":234,"mtime":1718980698332,"results":"231","hashOfConfig":"224"},{"size":81,"mtime":1729092985470,"results":"232","hashOfConfig":"224"},{"size":4074,"mtime":1729092985470,"results":"233","hashOfConfig":"224"},{"size":2193,"mtime":1729092985470,"results":"234","hashOfConfig":"224"},{"size":692,"mtime":1729092985470,"results":"235","hashOfConfig":"224"},{"size":5797,"mtime":1729092985471,"results":"236","hashOfConfig":"224"},{"size":1116,"mtime":1729092985473,"results":"237","hashOfConfig":"224"},{"size":373,"mtime":1729092985474,"results":"238","hashOfConfig":"224"},{"size":140223,"mtime":1729092985474,"results":"239","hashOfConfig":"224"},{"size":1936,"mtime":1729092985475,"results":"240","hashOfConfig":"224"},{"size":1547,"mtime":1729092985475,"results":"241","hashOfConfig":"224"},{"size":1423,"mtime":1729092985475,"results":"242","hashOfConfig":"224"},{"size":17991,"mtime":1729092985475,"results":"243","hashOfConfig":"224"},{"size":4687,"mtime":1729092985476,"results":"244","hashOfConfig":"224"},{"size":119,"mtime":1729092985476,"results":"245","hashOfConfig":"224"},{"size":4021,"mtime":1729092985477,"results":"246","hashOfConfig":"224"},{"size":2157,"mtime":1729092985477,"results":"247","hashOfConfig":"224"},{"size":104,"mtime":1729092985477,"results":"248","hashOfConfig":"224"},{"size":3388,"mtime":1729092985478,"results":"249","hashOfConfig":"224"},{"size":4803,"mtime":1729092985478,"results":"250","hashOfConfig":"224"},{"size":2528,"mtime":1729092985478,"results":"251","hashOfConfig":"224"},{"size":1301,"mtime":1729092985479,"results":"252","hashOfConfig":"224"},{"size":407,"mtime":1729048412105,"results":"253","hashOfConfig":"224"},{"size":614,"mtime":1729092985479,"results":"254","hashOfConfig":"224"},{"size":9238,"mtime":1729092985479,"results":"255","hashOfConfig":"224"},{"size":13057,"mtime":1729092985480,"results":"256","hashOfConfig":"224"},{"size":1485,"mtime":1729092985480,"results":"257","hashOfConfig":"224"},{"size":1379,"mtime":1729092985480,"results":"258","hashOfConfig":"224"},{"size":4273,"mtime":1729092985481,"results":"259","hashOfConfig":"224"},{"size":2192,"mtime":1729092985481,"results":"260","hashOfConfig":"224"},{"size":3785,"mtime":1729092985481,"results":"261","hashOfConfig":"224"},{"size":173751,"mtime":1729093405718,"results":"262","hashOfConfig":"224"},{"size":2418,"mtime":1729092985482,"results":"263","hashOfConfig":"224"},{"size":6212,"mtime":1729092985482,"results":"264","hashOfConfig":"224"},{"size":2145,"mtime":1729092985482,"results":"265","hashOfConfig":"224"},{"size":129,"mtime":1729092985483,"results":"266","hashOfConfig":"224"},{"size":12081,"mtime":1729092985483,"results":"267","hashOfConfig":"224"},{"size":4486,"mtime":1729092985483,"results":"268","hashOfConfig":"224"},{"size":173169,"mtime":1729092985484,"results":"269","hashOfConfig":"224"},{"size":680,"mtime":1729092985484,"results":"270","hashOfConfig":"224"},{"size":19776,"mtime":1729092985485,"results":"271","hashOfConfig":"224"},{"size":1947,"mtime":1729092985485,"results":"272","hashOfConfig":"224"},{"size":3309,"mtime":1729092985485,"results":"273","hashOfConfig":"224"},{"size":8111,"mtime":1729092985485,"results":"274","hashOfConfig":"224"},{"size":1021,"mtime":1729092985486,"results":"275","hashOfConfig":"224"},{"size":3695,"mtime":1729092985486,"results":"276","hashOfConfig":"224"},{"size":4063,"mtime":1729092985486,"results":"277","hashOfConfig":"224"},{"size":2414,"mtime":1729092985486,"results":"278","hashOfConfig":"224"},{"size":1984,"mtime":1729092985487,"results":"279","hashOfConfig":"224"},{"size":2832,"mtime":1729092985487,"results":"280","hashOfConfig":"224"},{"size":2368,"mtime":1729092985487,"results":"281","hashOfConfig":"224"},{"size":2069,"mtime":1729092985487,"results":"282","hashOfConfig":"224"},{"size":2861,"mtime":1729092985487,"results":"283","hashOfConfig":"224"},{"size":2416,"mtime":1729092985488,"results":"284","hashOfConfig":"224"},{"size":1996,"mtime":1729092985488,"results":"285","hashOfConfig":"224"},{"size":2830,"mtime":1729092985488,"results":"286","hashOfConfig":"224"},{"size":2370,"mtime":1729092985488,"results":"287","hashOfConfig":"224"},{"size":2069,"mtime":1729092985488,"results":"288","hashOfConfig":"224"},{"size":2863,"mtime":1729092985489,"results":"289","hashOfConfig":"224"},{"size":12424,"mtime":1729092985489,"results":"290","hashOfConfig":"224"},{"size":1824,"mtime":1729092985489,"results":"291","hashOfConfig":"224"},{"size":2591,"mtime":1729092985489,"results":"292","hashOfConfig":"224"},{"size":8673,"mtime":1729092985490,"results":"293","hashOfConfig":"224"},{"size":2349,"mtime":1729092985490,"results":"294","hashOfConfig":"224"},{"size":3571,"mtime":1729092985490,"results":"295","hashOfConfig":"224"},{"size":4693,"mtime":1729092985490,"results":"296","hashOfConfig":"224"},{"size":379,"mtime":1729092985491,"results":"297","hashOfConfig":"224"},{"size":2360,"mtime":1729092985491,"results":"298","hashOfConfig":"224"},{"size":359,"mtime":1729092985491,"results":"299","hashOfConfig":"224"},{"size":280,"mtime":1729092985491,"results":"300","hashOfConfig":"224"},{"size":477,"mtime":1709750569546,"results":"301","hashOfConfig":"224"},{"size":11478,"mtime":1729092985491,"results":"302","hashOfConfig":"224"},{"size":1798,"mtime":1729092985492,"results":"303","hashOfConfig":"224"},{"size":1522,"mtime":1729092985492,"results":"304","hashOfConfig":"224"},{"size":2968,"mtime":1729092985492,"results":"305","hashOfConfig":"224"},{"size":1562,"mtime":1729092985492,"results":"306","hashOfConfig":"224"},{"size":1505,"mtime":1729092985492,"results":"307","hashOfConfig":"224"},{"size":4928,"mtime":1729092985493,"results":"308","hashOfConfig":"224"},{"size":2096,"mtime":1729092985493,"results":"309","hashOfConfig":"224"},{"size":2017,"mtime":1729092985493,"results":"310","hashOfConfig":"224"},{"size":3008,"mtime":1729092985493,"results":"311","hashOfConfig":"224"},{"size":1939,"mtime":1729092985494,"results":"312","hashOfConfig":"224"},{"size":1830,"mtime":1729092985494,"results":"313","hashOfConfig":"224"},{"size":2400,"mtime":1729092985494,"results":"314","hashOfConfig":"224"},{"size":2081,"mtime":1729092985494,"results":"315","hashOfConfig":"224"},{"size":1833,"mtime":1729092985494,"results":"316","hashOfConfig":"224"},{"size":3039,"mtime":1729092985495,"results":"317","hashOfConfig":"224"},{"size":1935,"mtime":1729092985495,"results":"318","hashOfConfig":"224"},{"size":1863,"mtime":1729092985495,"results":"319","hashOfConfig":"224"},{"size":2271,"mtime":1729092985496,"results":"320","hashOfConfig":"224"},{"size":4492,"mtime":1729092985496,"results":"321","hashOfConfig":"224"},{"size":1265,"mtime":1729092985496,"results":"322","hashOfConfig":"224"},{"size":1705,"mtime":1729092985497,"results":"323","hashOfConfig":"224"},{"size":3575,"mtime":1729092985497,"results":"324","hashOfConfig":"224"},{"size":2108,"mtime":1729092985497,"results":"325","hashOfConfig":"224"},{"size":1840,"mtime":1729092985497,"results":"326","hashOfConfig":"224"},{"size":2913,"mtime":1729092985498,"results":"327","hashOfConfig":"224"},{"size":1518,"mtime":1729092985498,"results":"328","hashOfConfig":"224"},{"size":2104,"mtime":1729092985498,"results":"329","hashOfConfig":"224"},{"size":4365,"mtime":1729092985499,"results":"330","hashOfConfig":"224"},{"size":2385,"mtime":1729092985499,"results":"331","hashOfConfig":"224"},{"size":3711,"mtime":1729092985499,"results":"332","hashOfConfig":"224"},{"size":2049,"mtime":1729092985499,"results":"333","hashOfConfig":"224"},{"size":81524,"mtime":1729092985500,"results":"334","hashOfConfig":"224"},{"size":3754,"mtime":1729092985500,"results":"335","hashOfConfig":"224"},{"size":75960,"mtime":1729092985500,"results":"336","hashOfConfig":"224"},{"size":35,"mtime":1729092985501,"results":"337","hashOfConfig":"224"},{"size":330,"mtime":1729092985503,"results":"338","hashOfConfig":"224"},{"size":428,"mtime":1729092985503,"results":"339","hashOfConfig":"224"},{"size":1446,"mtime":1729092985503,"results":"340","hashOfConfig":"224"},{"size":2557,"mtime":1729092985503,"results":"341","hashOfConfig":"224"},{"size":11832,"mtime":1729092985504,"results":"342","hashOfConfig":"224"},{"size":516,"mtime":1729092985504,"results":"343","hashOfConfig":"224"},{"size":1254,"mtime":1729092985504,"results":"344","hashOfConfig":"224"},{"size":674,"mtime":1729092985504,"results":"345","hashOfConfig":"224"},{"size":333,"mtime":1729092985505,"results":"346","hashOfConfig":"224"},{"size":269,"mtime":1707759063050,"results":"347","hashOfConfig":"224"},{"size":892,"mtime":1729092985505,"results":"348","hashOfConfig":"224"},{"size":710,"mtime":1729092985505,"results":"349","hashOfConfig":"224"},{"size":348,"mtime":1707930494387,"results":"350","hashOfConfig":"224"},{"size":145,"mtime":1729092985505,"results":"351","hashOfConfig":"224"},{"size":667,"mtime":1729092985506,"results":"352","hashOfConfig":"224"},{"size":87,"mtime":1729092985506,"results":"353","hashOfConfig":"224"},{"size":784,"mtime":1729092985506,"results":"354","hashOfConfig":"224"},{"size":250,"mtime":1729092985506,"results":"355","hashOfConfig":"224"},{"size":443,"mtime":1729092985506,"results":"356","hashOfConfig":"224"},{"size":57,"mtime":1729092985507,"results":"357","hashOfConfig":"224"},{"size":76,"mtime":1729092985507,"results":"358","hashOfConfig":"224"},{"size":361,"mtime":1729092985507,"results":"359","hashOfConfig":"224"},{"size":268,"mtime":1729092985507,"results":"360","hashOfConfig":"224"},{"size":153,"mtime":1729092985508,"results":"361","hashOfConfig":"224"},{"size":74,"mtime":1729092985508,"results":"362","hashOfConfig":"224"},{"size":250,"mtime":1729092985508,"results":"363","hashOfConfig":"224"},{"size":172,"mtime":1729092985508,"results":"364","hashOfConfig":"224"},{"size":72,"mtime":1729092985509,"results":"365","hashOfConfig":"224"},{"size":262,"mtime":1729092985509,"results":"366","hashOfConfig":"224"},{"size":179,"mtime":1729092985509,"results":"367","hashOfConfig":"224"},{"size":76,"mtime":1729092985509,"results":"368","hashOfConfig":"224"},{"size":314,"mtime":1729092985510,"results":"369","hashOfConfig":"224"},{"size":121,"mtime":1729092985510,"results":"370","hashOfConfig":"224"},{"size":62,"mtime":1729092985510,"results":"371","hashOfConfig":"224"},{"size":182,"mtime":1729092985510,"results":"372","hashOfConfig":"224"},{"size":204,"mtime":1729092985510,"results":"373","hashOfConfig":"224"},{"size":64,"mtime":1729092985511,"results":"374","hashOfConfig":"224"},{"size":1192,"mtime":1729092985511,"results":"375","hashOfConfig":"224"},{"size":181,"mtime":1729092985511,"results":"376","hashOfConfig":"224"},{"size":83,"mtime":1729092985512,"results":"377","hashOfConfig":"224"},{"size":62,"mtime":1729092985512,"results":"378","hashOfConfig":"224"},{"size":193,"mtime":1729092985512,"results":"379","hashOfConfig":"224"},{"size":173,"mtime":1729092985512,"results":"380","hashOfConfig":"224"},{"size":68,"mtime":1729092985512,"results":"381","hashOfConfig":"224"},{"size":523,"mtime":1729092985513,"results":"382","hashOfConfig":"224"},{"size":655,"mtime":1729092985513,"results":"383","hashOfConfig":"224"},{"size":211,"mtime":1729092985513,"results":"384","hashOfConfig":"224"},{"size":218,"mtime":1729092985513,"results":"385","hashOfConfig":"224"},{"size":142,"mtime":1729092985513,"results":"386","hashOfConfig":"224"},{"size":2032,"mtime":1729092985514,"results":"387","hashOfConfig":"224"},{"size":27,"mtime":1676660448779,"results":"388","hashOfConfig":"224"},{"size":1140,"mtime":1729092985514,"results":"389","hashOfConfig":"224"},{"size":73,"mtime":1676660448779,"results":"390","hashOfConfig":"224"},{"size":191,"mtime":1729092985514,"results":"391","hashOfConfig":"224"},{"size":676,"mtime":1729092985514,"results":"392","hashOfConfig":"224"},{"size":413,"mtime":1729092985515,"results":"393","hashOfConfig":"224"},{"size":35,"mtime":1707759063055,"results":"394","hashOfConfig":"224"},{"size":80,"mtime":1729092985515,"results":"395","hashOfConfig":"224"},{"size":302,"mtime":1729092985515,"results":"396","hashOfConfig":"224"},{"size":235,"mtime":1729092985516,"results":"397","hashOfConfig":"224"},{"size":483,"mtime":1729092985516,"results":"398","hashOfConfig":"224"},{"size":768,"mtime":1729092985516,"results":"399","hashOfConfig":"224"},{"size":143,"mtime":1718980698346,"results":"400","hashOfConfig":"224"},{"size":201,"mtime":1729092985516,"results":"401","hashOfConfig":"224"},{"size":5379,"mtime":1729092985517,"results":"402","hashOfConfig":"224"},{"size":5750,"mtime":1729092985517,"results":"403","hashOfConfig":"224"},{"size":1221,"mtime":1729092985518,"results":"404","hashOfConfig":"224"},{"size":58669,"mtime":1729092985518,"results":"405","hashOfConfig":"224"},{"size":4113,"mtime":1729092985519,"results":"406","hashOfConfig":"224"},{"size":26368,"mtime":1729092985519,"results":"407","hashOfConfig":"224"},{"size":6431,"mtime":1729092985519,"results":"408","hashOfConfig":"224"},{"size":3632,"mtime":1729092985520,"results":"409","hashOfConfig":"224"},{"size":1671,"mtime":1729092985520,"results":"410","hashOfConfig":"224"},{"size":138,"mtime":1729092985520,"results":"411","hashOfConfig":"224"},{"size":255,"mtime":1729092985520,"results":"412","hashOfConfig":"224"},{"size":2679,"mtime":1729092985521,"results":"413","hashOfConfig":"224"},{"size":2422,"mtime":1729092985521,"results":"414","hashOfConfig":"224"},{"size":4771,"mtime":1729092985521,"results":"415","hashOfConfig":"224"},{"size":4621,"mtime":1729092985521,"results":"416","hashOfConfig":"224"},{"size":29680,"mtime":1729092985522,"results":"417","hashOfConfig":"224"},{"size":447,"mtime":1727884737848,"results":"418","hashOfConfig":"224"},{"size":1551,"mtime":1729092985522,"results":"419","hashOfConfig":"224"},{"size":6318,"mtime":1729092985522,"results":"420","hashOfConfig":"224"},{"size":1716,"mtime":1729092985522,"results":"421","hashOfConfig":"224"},{"size":492,"mtime":1729092985522,"results":"422","hashOfConfig":"423"},{"size":1575,"mtime":1729092985523,"results":"424","hashOfConfig":"423"},{"size":343,"mtime":1729092985523,"results":"425","hashOfConfig":"423"},{"size":303,"mtime":1729092985523,"results":"426","hashOfConfig":"423"},{"size":335,"mtime":1729092985523,"results":"427","hashOfConfig":"423"},{"size":351,"mtime":1729092985524,"results":"428","hashOfConfig":"423"},{"size":369,"mtime":1729092985524,"results":"429","hashOfConfig":"423"},{"size":440,"mtime":1729092985524,"results":"430","hashOfConfig":"423"},{"size":350,"mtime":1729092985524,"results":"431","hashOfConfig":"423"},{"size":301,"mtime":1729092985525,"results":"432","hashOfConfig":"423"},{"size":570,"mtime":1729092985525,"results":"433","hashOfConfig":"423"},{"size":792,"mtime":1729092985525,"results":"434","hashOfConfig":"423"},{"size":312,"mtime":1729092985525,"results":"435","hashOfConfig":"423"},{"size":293,"mtime":1729092985525,"results":"436","hashOfConfig":"423"},{"size":362,"mtime":1729092985525,"results":"437","hashOfConfig":"423"},{"size":361,"mtime":1729092985526,"results":"438","hashOfConfig":"423"},{"size":431,"mtime":1729092985526,"results":"439","hashOfConfig":"423"},{"size":274,"mtime":1729092985526,"results":"440","hashOfConfig":"423"},{"size":361,"mtime":1729092985526,"results":"441","hashOfConfig":"423"},{"size":1781,"mtime":1729092985527,"results":"442","hashOfConfig":"423"},{"size":702,"mtime":1729092985527,"results":"443","hashOfConfig":"224"},{"size":2229,"mtime":1729092985527,"results":"444","hashOfConfig":"224"},{"size":5173,"mtime":1729092985527,"results":"445","hashOfConfig":"224"},{"size":1668,"mtime":1729092985527,"results":"446","hashOfConfig":"224"},{"filePath":"447","messages":"448","suppressedMessages":"449","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"105205t",{"filePath":"450","messages":"451","suppressedMessages":"452","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"453","messages":"454","suppressedMessages":"455","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"456","messages":"457","suppressedMessages":"458","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"459","messages":"460","suppressedMessages":"461","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"462","messages":"463","suppressedMessages":"464","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"465","messages":"466","suppressedMessages":"467","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"468","messages":"469","suppressedMessages":"470","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"471","messages":"472","suppressedMessages":"473","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"474","messages":"475","suppressedMessages":"476","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"477","messages":"478","suppressedMessages":"479","errorCount":0,"fatalErrorCount":0,"warningCount":15,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"480","messages":"481","suppressedMessages":"482","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"483","messages":"484","suppressedMessages":"485","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"486","messages":"487","suppressedMessages":"488","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"489","messages":"490","suppressedMessages":"491","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"492","messages":"493","suppressedMessages":"494","errorCount":0,"fatalErrorCount":0,"warningCount":27,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"495","messages":"496","suppressedMessages":"497","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"498","messages":"499","suppressedMessages":"500","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"501","messages":"502","suppressedMessages":"503","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"504","messages":"505","suppressedMessages":"506","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"507","messages":"508","suppressedMessages":"509","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"510","messages":"511","suppressedMessages":"512","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"513","messages":"514","suppressedMessages":"515","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"516","messages":"517","suppressedMessages":"518","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"519","messages":"520","suppressedMessages":"521","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"522","messages":"523","suppressedMessages":"524","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"525","messages":"526","suppressedMessages":"527","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"528","messages":"529","suppressedMessages":"530","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"531","messages":"532","suppressedMessages":"533","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"534","messages":"535","suppressedMessages":"536","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"537","messages":"538","suppressedMessages":"539","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"540","messages":"541","suppressedMessages":"542","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"543","messages":"544","suppressedMessages":"545","errorCount":0,"fatalErrorCount":0,"warningCount":24,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"546","messages":"547","suppressedMessages":"548","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"549","messages":"550","suppressedMessages":"551","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"552","messages":"553","suppressedMessages":"554","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"555","messages":"556","suppressedMessages":"557","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"558","messages":"559","suppressedMessages":"560","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"561","messages":"562","suppressedMessages":"563","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"564","messages":"565","suppressedMessages":"566","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"567","messages":"568","suppressedMessages":"569","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"570","messages":"571","suppressedMessages":"572","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"573","messages":"574","suppressedMessages":"575","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"576","messages":"577","suppressedMessages":"578","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"579","messages":"580","suppressedMessages":"581","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"582","messages":"583","suppressedMessages":"584","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"585","messages":"586","suppressedMessages":"587","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"588","messages":"589","suppressedMessages":"590","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"591","messages":"592","suppressedMessages":"593","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"594","messages":"595","suppressedMessages":"596","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"597","messages":"598","suppressedMessages":"599","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"600","messages":"601","suppressedMessages":"602","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"603","messages":"604","suppressedMessages":"605","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"606","messages":"607","suppressedMessages":"608","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"609","messages":"610","suppressedMessages":"611","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"612","messages":"613","suppressedMessages":"614","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"615","messages":"616","suppressedMessages":"617","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"618","messages":"619","suppressedMessages":"620","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"621","messages":"622","suppressedMessages":"623","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"624","messages":"625","suppressedMessages":"626","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"627","messages":"628","suppressedMessages":"629","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"630","messages":"631","suppressedMessages":"632","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"633","messages":"634","suppressedMessages":"635","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"636","messages":"637","suppressedMessages":"638","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"639","messages":"640","suppressedMessages":"641","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"642","messages":"643","suppressedMessages":"644","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"645","messages":"646","suppressedMessages":"647","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"648","messages":"649","suppressedMessages":"650","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"651","messages":"652","suppressedMessages":"653","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"654","messages":"655","suppressedMessages":"656","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"657","messages":"658","suppressedMessages":"659","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"660","messages":"661","suppressedMessages":"662","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"663","messages":"664","suppressedMessages":"665","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"666","messages":"667","suppressedMessages":"668","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"669","messages":"670","suppressedMessages":"671","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"672","messages":"673","suppressedMessages":"674","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"675","messages":"676","suppressedMessages":"677","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"678","messages":"679","suppressedMessages":"680","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"681","messages":"682","suppressedMessages":"683","errorCount":0,"fatalErrorCount":0,"warningCount":11,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"684","messages":"685","suppressedMessages":"686","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"687","messages":"688","suppressedMessages":"689","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"690","messages":"691","suppressedMessages":"692","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"693","messages":"694","suppressedMessages":"695","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"696","messages":"697","suppressedMessages":"698","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"699","messages":"700","suppressedMessages":"701","errorCount":0,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"702","messages":"703","suppressedMessages":"704","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"705","messages":"706","suppressedMessages":"707","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"708","messages":"709","suppressedMessages":"710","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"711","messages":"712","suppressedMessages":"713","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"714","messages":"715","suppressedMessages":"716","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"717","messages":"718","suppressedMessages":"719","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"720","messages":"721","suppressedMessages":"722","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"723","messages":"724","suppressedMessages":"725","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"726","messages":"727","suppressedMessages":"728","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"729","messages":"730","suppressedMessages":"731","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"732","messages":"733","suppressedMessages":"734","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"735","messages":"736","suppressedMessages":"737","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"738","messages":"739","suppressedMessages":"740","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"741","messages":"742","suppressedMessages":"743","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"744","messages":"745","suppressedMessages":"746","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"747","messages":"748","suppressedMessages":"749","errorCount":0,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"750","messages":"751","suppressedMessages":"752","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"753","messages":"754","suppressedMessages":"755","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"756","messages":"757","suppressedMessages":"758","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"759","messages":"760","suppressedMessages":"761","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"762","messages":"763","suppressedMessages":"764","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"765","messages":"766","suppressedMessages":"767","errorCount":0,"fatalErrorCount":0,"warningCount":9,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"768","messages":"769","suppressedMessages":"770","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"771","messages":"772","suppressedMessages":"773","errorCount":0,"fatalErrorCount":0,"warningCount":8,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"774","messages":"775","suppressedMessages":"776","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"777","messages":"778","suppressedMessages":"779","errorCount":0,"fatalErrorCount":0,"warningCount":167,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"780","messages":"781","suppressedMessages":"782","errorCount":0,"fatalErrorCount":0,"warningCount":15,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"783","messages":"784","suppressedMessages":"785","errorCount":0,"fatalErrorCount":0,"warningCount":85,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"786","messages":"787","suppressedMessages":"788","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"789","messages":"790","suppressedMessages":"791","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"792","messages":"793","suppressedMessages":"794","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"795","messages":"796","suppressedMessages":"797","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"798","messages":"799","suppressedMessages":"800","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"801","messages":"802","suppressedMessages":"803","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"804","messages":"805","suppressedMessages":"806","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"807","messages":"808","suppressedMessages":"809","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"810","messages":"811","suppressedMessages":"812","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"813","messages":"814","suppressedMessages":"815","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"816","messages":"817","suppressedMessages":"818","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"819","messages":"820","suppressedMessages":"821","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"822","messages":"823","suppressedMessages":"824","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"825","messages":"826","suppressedMessages":"827","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"828","messages":"829","suppressedMessages":"830","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"831","messages":"832","suppressedMessages":"833","errorCount":0,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"834","messages":"835","suppressedMessages":"836","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"837","messages":"838","suppressedMessages":"839","errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"840","messages":"841","suppressedMessages":"842","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"843","messages":"844","suppressedMessages":"845","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"846","messages":"847","suppressedMessages":"848","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"849","messages":"850","suppressedMessages":"851","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"852","messages":"853","suppressedMessages":"854","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"855","messages":"856","suppressedMessages":"857","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"858","messages":"859","suppressedMessages":"860","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"861","messages":"862","suppressedMessages":"863","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"864","messages":"865","suppressedMessages":"866","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"867","messages":"868","suppressedMessages":"869","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"870","messages":"871","suppressedMessages":"872","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"873","messages":"874","suppressedMessages":"875","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"876","messages":"877","suppressedMessages":"878","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"879","messages":"880","suppressedMessages":"881","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"882","messages":"883","suppressedMessages":"884","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"885","messages":"886","suppressedMessages":"887","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"888","messages":"889","suppressedMessages":"890","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"891","messages":"892","suppressedMessages":"893","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"894","messages":"895","suppressedMessages":"896","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"897","messages":"898","suppressedMessages":"899","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"900","messages":"901","suppressedMessages":"902","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"903","messages":"904","suppressedMessages":"905","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"906","messages":"907","suppressedMessages":"908","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"909","messages":"910","suppressedMessages":"911","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"912","messages":"913","suppressedMessages":"914","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"915","messages":"916","suppressedMessages":"917","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"918","messages":"919","suppressedMessages":"920","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"921","messages":"922","suppressedMessages":"923","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"924","messages":"925","suppressedMessages":"926","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"927","messages":"928","suppressedMessages":"929","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"930","messages":"931","suppressedMessages":"932","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"933","messages":"934","suppressedMessages":"935","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"936","messages":"937","suppressedMessages":"938","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"939","messages":"940","suppressedMessages":"941","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"942","messages":"943","suppressedMessages":"944","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"945","messages":"946","suppressedMessages":"947","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"948","messages":"949","suppressedMessages":"950","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"951","messages":"952","suppressedMessages":"953","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"954","messages":"955","suppressedMessages":"956","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"957","messages":"958","suppressedMessages":"959","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"960","messages":"961","suppressedMessages":"962","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"963","messages":"964","suppressedMessages":"965","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"966","messages":"967","suppressedMessages":"968","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"969","messages":"970","suppressedMessages":"971","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"972","messages":"973","suppressedMessages":"974","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"975","messages":"976","suppressedMessages":"977","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"978","messages":"979","suppressedMessages":"980","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"981","messages":"982","suppressedMessages":"983","errorCount":0,"fatalErrorCount":0,"warningCount":20,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"984","messages":"985","suppressedMessages":"986","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"987","messages":"988","suppressedMessages":"989","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"990","messages":"991","suppressedMessages":"992","errorCount":0,"fatalErrorCount":0,"warningCount":16,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"993","messages":"994","suppressedMessages":"995","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"996","messages":"997","suppressedMessages":"998","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"999","messages":"1000","suppressedMessages":"1001","errorCount":0,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"1002","messages":"1003","suppressedMessages":"1004","errorCount":0,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"1005","messages":"1006","suppressedMessages":"1007","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1008","messages":"1009","suppressedMessages":"1010","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1011","messages":"1012","suppressedMessages":"1013","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"1014","messages":"1015","suppressedMessages":"1016","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"1017","messages":"1018","suppressedMessages":"1019","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"1020","messages":"1021","suppressedMessages":"1022","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"1023","messages":"1024","suppressedMessages":"1025","errorCount":0,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"1026","messages":"1027","suppressedMessages":"1028","errorCount":0,"fatalErrorCount":0,"warningCount":67,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"1029","messages":"1030","suppressedMessages":"1031","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1032","messages":"1033","suppressedMessages":"1034","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"1035","messages":"1036","suppressedMessages":"1037","errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"1038","messages":"1039","suppressedMessages":"1040","errorCount":0,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"1041","messages":"1042","suppressedMessages":"1043","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"5kwgi0",{"filePath":"1044","messages":"1045","suppressedMessages":"1046","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1047","messages":"1048","suppressedMessages":"1049","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1050","messages":"1051","suppressedMessages":"1052","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1053","messages":"1054","suppressedMessages":"1055","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1056","messages":"1057","suppressedMessages":"1058","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1059","messages":"1060","suppressedMessages":"1061","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1062","messages":"1063","suppressedMessages":"1064","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1065","messages":"1066","suppressedMessages":"1067","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1068","messages":"1069","suppressedMessages":"1070","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1071","messages":"1072","suppressedMessages":"1073","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1074","messages":"1075","suppressedMessages":"1076","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1077","messages":"1078","suppressedMessages":"1079","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1080","messages":"1081","suppressedMessages":"1082","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1083","messages":"1084","suppressedMessages":"1085","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1086","messages":"1087","suppressedMessages":"1088","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1089","messages":"1090","suppressedMessages":"1091","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1092","messages":"1093","suppressedMessages":"1094","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1095","messages":"1096","suppressedMessages":"1097","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1098","messages":"1099","suppressedMessages":"1100","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"1101","messages":"1102","suppressedMessages":"1103","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"1104","messages":"1105","suppressedMessages":"1106","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"1107","messages":"1108","suppressedMessages":"1109","errorCount":0,"fatalErrorCount":0,"warningCount":31,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"1110","messages":"1111","suppressedMessages":"1112","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},"/Users/brendanjbond/Projects/formio/core/src/process/validation/__tests__/Validator.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateTime.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateTime.ts",["1113"],[],"/Users/brendanjbond/Projects/formio/core/src/ejs.d.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/error/FieldError.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/error/ProcessorError.ts",["1114","1115"],[],"/Users/brendanjbond/Projects/formio/core/src/error/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/modules/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/modules/jsonlogic/__tests__/operators.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/modules/jsonlogic/index.ts",["1116","1117","1118","1119","1120","1121","1122","1123","1124","1125","1126","1127","1128","1129","1130"],[],"/Users/brendanjbond/Projects/formio/core/src/modules/jsonlogic/jsonLogic.ts",["1131","1132","1133"],[],"/Users/brendanjbond/Projects/formio/core/src/modules/jsonlogic/operators.ts",["1134"],[],"/Users/brendanjbond/Projects/formio/core/src/process/__tests__/fixtures/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/__tests__/fixtures/util.ts",["1135"],[],"/Users/brendanjbond/Projects/formio/core/src/process/__tests__/process.test.ts",["1136","1137","1138","1139","1140","1141","1142","1143","1144","1145","1146","1147","1148","1149","1150","1151","1152","1153","1154","1155","1156","1157","1158","1159","1160","1161","1162"],[],"/Users/brendanjbond/Projects/formio/core/src/process/calculation/__tests__/calculation.test.ts",["1163","1164"],[],"/Users/brendanjbond/Projects/formio/core/src/process/calculation/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/clearHidden.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/conditions/__tests__/conditions.test.ts",["1165","1166"],[],"/Users/brendanjbond/Projects/formio/core/src/process/conditions/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/defaultValue/__tests__/defaultValue.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/defaultValue/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/dereference/index.ts",["1167","1168"],[],"/Users/brendanjbond/Projects/formio/core/src/process/fetch/__tests__/fetch.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/fetch/index.ts",["1169","1170","1171"],[],"/Users/brendanjbond/Projects/formio/core/src/process/filter/__tests__/filter.test.ts",["1172","1173","1174","1175"],[],"/Users/brendanjbond/Projects/formio/core/src/process/filter/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/hideChildren.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/logic/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/normalize/__tests__/normalize.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/normalize/index.ts",["1176","1177","1178","1179","1180","1181","1182","1183","1184","1185","1186","1187","1188","1189","1190","1191","1192","1193","1194","1195","1196","1197","1198","1199"],[],"/Users/brendanjbond/Projects/formio/core/src/process/populate/__tests__/populate.test.ts",["1200","1201"],[],"/Users/brendanjbond/Projects/formio/core/src/process/populate/index.ts",["1202"],[],"/Users/brendanjbond/Projects/formio/core/src/process/process.ts",["1203","1204"],[],"/Users/brendanjbond/Projects/formio/core/src/process/processOne.ts",["1205","1206","1207"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/__tests__/fixtures/components.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/__tests__/fixtures/forms.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/__tests__/multiple.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/__tests__/util.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/i18n/en.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/i18n/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/index.ts",["1208"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/fixtures/components.ts",["1209"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/fixtures/forms.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/fixtures/util.ts",["1210"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateAvailableItems.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateCustom.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateDate.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateDay.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateEmail.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateJson.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMask.test.ts",["1211"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMaximumDay.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMaximumLength.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMaximumSelectedCount.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMaximumValue.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMaximumWords.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMaximumYear.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMinimumDay.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMinimumLength.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMinimumSelectedCount.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMinimumValue.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMinimumWords.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMinimumYear.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateMultiple.test.ts",["1212","1213","1214","1215"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateNumber.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateRegexPattern.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateRequired.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateRequiredDay.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateUrl.test.ts",["1216","1217","1218"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/__tests__/validateUrlSelectValue.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/asynchronousRules.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/clientRules.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/databaseRules.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/evaluationRules.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateAvailableItems.ts",["1219","1220","1221","1222","1223","1224","1225","1226","1227","1228","1229"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateCustom.ts",["1230"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateDate.ts",["1231","1232"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateDay.ts",["1233"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateEmail.ts",["1234"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateJson.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMask.ts",["1235","1236","1237","1238","1239"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMaximumDay.ts",["1240"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMaximumLength.ts",["1241","1242"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMaximumSelectedCount.ts",["1243","1244","1245"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMaximumValue.ts",["1246","1247"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMaximumWords.ts",["1248","1249"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMaximumYear.ts",["1250"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMinimumDay.ts",["1251"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMinimumLength.ts",["1252"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMinimumSelectedCount.ts",["1253","1254","1255"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMinimumValue.ts",["1256","1257"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMinimumWords.ts",["1258"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMinimumYear.ts",["1259"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateMultiple.ts",["1260"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateNumber.ts",["1261"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateRegexPattern.ts",["1262"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateRequired.ts",["1263","1264","1265","1266","1267"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateRequiredDay.ts",["1268"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateRequiredSurvey.ts",["1269","1270"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateResourceSelectValue.ts",["1271","1272","1273","1274"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateUnique.ts",["1275"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateUrl.ts",["1276"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateUrlSelectValue.ts",["1277","1278","1279","1280","1281","1282","1283","1284","1285"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/rules/validateValueProperty.ts",["1286","1287"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/util.ts",["1288","1289","1290","1291","1292","1293","1294","1295"],[],"/Users/brendanjbond/Projects/formio/core/src/process/validation/validate.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/sdk/Formio.ts",["1296","1297","1298","1299","1300","1301","1302","1303","1304","1305","1306","1307","1308","1309","1310","1311","1312","1313","1314","1315","1316","1317","1318","1319","1320","1321","1322","1323","1324","1325","1326","1327","1328","1329","1330","1331","1332","1333","1334","1335","1336","1337","1338","1339","1340","1341","1342","1343","1344","1345","1346","1347","1348","1349","1350","1351","1352","1353","1354","1355","1356","1357","1358","1359","1360","1361","1362","1363","1364","1365","1366","1367","1368","1369","1370","1371","1372","1373","1374","1375","1376","1377","1378","1379","1380","1381","1382","1383","1384","1385","1386","1387","1388","1389","1390","1391","1392","1393","1394","1395","1396","1397","1398","1399","1400","1401","1402","1403","1404","1405","1406","1407","1408","1409","1410","1411","1412","1413","1414","1415","1416","1417","1418","1419","1420","1421","1422","1423","1424","1425","1426","1427","1428","1429","1430","1431","1432","1433","1434","1435","1436","1437","1438","1439","1440","1441","1442","1443","1444","1445","1446","1447","1448","1449","1450","1451","1452","1453","1454","1455","1456","1457","1458","1459","1460","1461","1462"],[],"/Users/brendanjbond/Projects/formio/core/src/sdk/Plugins.ts",["1463","1464","1465","1466","1467","1468","1469","1470","1471","1472","1473","1474","1475","1476","1477"],[],"/Users/brendanjbond/Projects/formio/core/src/sdk/__tests__/Formio.test.ts",["1478","1479","1480","1481","1482","1483","1484","1485","1486","1487","1488","1489","1490","1491","1492","1493","1494","1495","1496","1497","1498","1499","1500","1501","1502","1503","1504","1505","1506","1507","1508","1509","1510","1511","1512","1513","1514","1515","1516","1517","1518","1519","1520","1521","1522","1523","1524","1525","1526","1527","1528","1529","1530","1531","1532","1533","1534","1535","1536","1537","1538","1539","1540","1541","1542","1543","1544","1545","1546","1547","1548","1549","1550","1551","1552","1553","1554","1555","1556","1557","1558","1559","1560","1561","1562"],["1563","1564","1565","1566","1567","1568","1569","1570","1571","1572","1573","1574","1575","1576","1577","1578","1579"],"/Users/brendanjbond/Projects/formio/core/src/sdk/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/Access.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/Action.ts",["1580"],[],"/Users/brendanjbond/Projects/formio/core/src/types/AdvancedLogic.ts",["1581"],[],"/Users/brendanjbond/Projects/formio/core/src/types/BaseComponent.ts",["1582","1583","1584","1585"],[],"/Users/brendanjbond/Projects/formio/core/src/types/Component.ts",["1586"],[],"/Users/brendanjbond/Projects/formio/core/src/types/DataObject.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/Form.ts",["1587"],[],"/Users/brendanjbond/Projects/formio/core/src/types/PassedComponentInstance.ts",["1588","1589","1590","1591"],[],"/Users/brendanjbond/Projects/formio/core/src/types/Role.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/RuleFn.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/Submission.ts",["1592","1593","1594"],[],"/Users/brendanjbond/Projects/formio/core/src/types/formUtil.ts",["1595","1596","1597"],[],"/Users/brendanjbond/Projects/formio/core/src/types/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessConfig.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessContext.ts",["1598","1599","1600","1601","1602"],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessType.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessorContext.ts",["1603","1604","1605","1606","1607","1608"],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessorFn.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessorInfo.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessorScope.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessorType.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/ProcessorsScope.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/calculation/CalculationContext.ts",["1609"],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/calculation/CalculationScope.ts",["1610"],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/calculation/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/conditions/ConditionsContext.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/conditions/ConditionsScope.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/conditions/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/defaultValue/DefaultValueContext.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/defaultValue/DefaultValueScope.ts",["1611","1612"],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/defaultValue/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/fetch/FetchContext.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/fetch/FetchScope.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/fetch/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/filter/FilterContext.ts",["1613"],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/filter/FilterScope.ts",["1614"],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/filter/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/index.ts",["1615","1616"],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/logic/LogicContext.ts",["1617"],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/logic/LogicScope.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/logic/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/populate/PopulateContext.ts",["1618"],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/populate/PopulateScope.ts",["1619","1620","1621"],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/populate/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/validation/ValidationContext.ts",["1622"],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/validation/ValidationFn.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/validation/ValidationRuleInfo.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/validation/ValidationScope.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/process/validation/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/project/Project.ts",["1623"],[],"/Users/brendanjbond/Projects/formio/core/src/types/project/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/project/settings/ProjectSettings.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/project/settings/authorization/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/project/settings/authorization/ldap.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/project/settings/authorization/oauth.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/project/settings/authorization/saml.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/project/settings/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/project/settings/integrations/captcha.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/project/settings/integrations/dataConnections.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/project/settings/integrations/eSign.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/project/settings/integrations/email.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/types/project/settings/integrations/fileStorage.ts",[],["1624"],"/Users/brendanjbond/Projects/formio/core/src/types/project/settings/integrations/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/Database.ts",["1625","1626"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/Evaluator.ts",["1627","1628","1629","1630","1631","1632","1633","1634","1635","1636","1637","1638","1639","1640","1641","1642","1643","1644","1645","1646"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/__tests__/Evaluator.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/__tests__/date.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/__tests__/formUtil.test.ts",["1647","1648","1649","1650","1651","1652","1653","1654","1655","1656","1657","1658","1659","1660","1661","1662"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/__tests__/jwtDecode.test.ts",["1663","1664"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/__tests__/unwind.test.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/conditions.ts",["1665","1666","1667","1668","1669"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/date.ts",["1670","1671","1672","1673","1674"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/dom.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/error.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/fastCloneDeep.ts",["1675","1676"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/formUtil/eachComponent.ts",["1677","1678","1679"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/formUtil/eachComponentAsync.ts",["1680","1681","1682"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/formUtil/eachComponentData.ts",["1683","1684","1685","1686"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/formUtil/eachComponentDataAsync.ts",["1687","1688","1689","1690","1691"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/formUtil/index.ts",["1692","1693","1694","1695","1696","1697","1698","1699","1700","1701","1702","1703","1704","1705","1706","1707","1708","1709","1710","1711","1712","1713","1714","1715","1716","1717","1718","1719","1720","1721","1722","1723","1724","1725","1726","1727","1728","1729","1730","1731","1732","1733","1734","1735","1736","1737","1738","1739","1740","1741","1742","1743","1744","1745","1746","1747","1748","1749","1750","1751","1752","1753","1754","1755","1756","1757","1758"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/index.ts",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/jwtDecode.ts",["1759","1760"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/logic.ts",["1761","1762","1763","1764","1765","1766"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/mask.ts",["1767","1768","1769","1770","1771"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/ConditionOperator.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/DateGreaterThan.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/DateGreaterThanOrEqual.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/DateLessThan.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/DateLessThanOrEqual.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/EndsWith.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/GreaterThan.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/GreaterThanOrEqual.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/Includes.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/IsDateEqual.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/IsEmptyValue.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/IsEqualTo.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/IsNotDateEqual.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/IsNotEmptyValue.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/IsNotEqualTo.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/LessThan.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/LessThanOrEqual.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/NotIncludes.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/StartsWith.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/operators/index.js",[],[],"/Users/brendanjbond/Projects/formio/core/src/utils/override.ts",["1772","1773","1774"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/sanitize.ts",["1775","1776","1777","1778"],[],"/Users/brendanjbond/Projects/formio/core/src/utils/unwind.ts",["1779","1780","1781","1782","1783","1784","1785","1786","1787","1788","1789","1790","1791","1792","1793","1794","1795","1796","1797","1798","1799","1800","1801","1802","1803","1804","1805","1806","1807","1808","1809"],["1810","1811"],"/Users/brendanjbond/Projects/formio/core/src/utils/utils.ts",["1812","1813"],[],{"ruleId":"1814","severity":1,"message":"1815","line":11,"column":43,"nodeType":"1816","messageId":"1817","endLine":11,"endColumn":46,"suggestions":"1818"},{"ruleId":"1814","severity":1,"message":"1815","line":3,"column":34,"nodeType":"1816","messageId":"1817","endLine":3,"endColumn":37,"suggestions":"1819"},{"ruleId":"1814","severity":1,"message":"1815","line":4,"column":58,"nodeType":"1816","messageId":"1817","endLine":4,"endColumn":61,"suggestions":"1820"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":11,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":14,"suggestions":"1821"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":11,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":14,"suggestions":"1822"},{"ruleId":"1814","severity":1,"message":"1815","line":7,"column":10,"nodeType":"1816","messageId":"1817","endLine":7,"endColumn":13,"suggestions":"1823"},{"ruleId":"1814","severity":1,"message":"1815","line":9,"column":14,"nodeType":"1816","messageId":"1817","endLine":9,"endColumn":17,"suggestions":"1824"},{"ruleId":"1814","severity":1,"message":"1815","line":28,"column":27,"nodeType":"1816","messageId":"1817","endLine":28,"endColumn":30,"suggestions":"1825"},{"ruleId":"1814","severity":1,"message":"1815","line":28,"column":35,"nodeType":"1816","messageId":"1817","endLine":28,"endColumn":38,"suggestions":"1826"},{"ruleId":"1814","severity":1,"message":"1815","line":29,"column":14,"nodeType":"1816","messageId":"1817","endLine":29,"endColumn":17,"suggestions":"1827"},{"ruleId":"1814","severity":1,"message":"1815","line":30,"column":18,"nodeType":"1816","messageId":"1817","endLine":30,"endColumn":21,"suggestions":"1828"},{"ruleId":"1814","severity":1,"message":"1815","line":33,"column":58,"nodeType":"1816","messageId":"1817","endLine":33,"endColumn":61,"suggestions":"1829"},{"ruleId":"1814","severity":1,"message":"1815","line":47,"column":32,"nodeType":"1816","messageId":"1817","endLine":47,"endColumn":35,"suggestions":"1830"},{"ruleId":"1814","severity":1,"message":"1815","line":48,"column":25,"nodeType":"1816","messageId":"1817","endLine":48,"endColumn":28,"suggestions":"1831"},{"ruleId":"1814","severity":1,"message":"1815","line":50,"column":33,"nodeType":"1816","messageId":"1817","endLine":50,"endColumn":36,"suggestions":"1832"},{"ruleId":"1814","severity":1,"message":"1815","line":70,"column":32,"nodeType":"1816","messageId":"1817","endLine":70,"endColumn":35,"suggestions":"1833"},{"ruleId":"1814","severity":1,"message":"1815","line":71,"column":25,"nodeType":"1816","messageId":"1817","endLine":71,"endColumn":28,"suggestions":"1834"},{"ruleId":"1814","severity":1,"message":"1815","line":75,"column":33,"nodeType":"1816","messageId":"1817","endLine":75,"endColumn":36,"suggestions":"1835"},{"ruleId":"1814","severity":1,"message":"1815","line":11,"column":43,"nodeType":"1816","messageId":"1817","endLine":11,"endColumn":46,"suggestions":"1836"},{"ruleId":"1814","severity":1,"message":"1815","line":16,"column":62,"nodeType":"1816","messageId":"1817","endLine":16,"endColumn":65,"suggestions":"1837"},{"ruleId":"1814","severity":1,"message":"1815","line":21,"column":62,"nodeType":"1816","messageId":"1817","endLine":21,"endColumn":65,"suggestions":"1838"},{"ruleId":"1814","severity":1,"message":"1815","line":249,"column":17,"nodeType":"1816","messageId":"1817","endLine":249,"endColumn":20,"suggestions":"1839"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":9,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":12,"suggestions":"1840"},{"ruleId":"1814","severity":1,"message":"1815","line":959,"column":19,"nodeType":"1816","messageId":"1817","endLine":959,"endColumn":22,"suggestions":"1841"},{"ruleId":"1814","severity":1,"message":"1815","line":1301,"column":19,"nodeType":"1816","messageId":"1817","endLine":1301,"endColumn":22,"suggestions":"1842"},{"ruleId":"1814","severity":1,"message":"1815","line":1497,"column":19,"nodeType":"1816","messageId":"1817","endLine":1497,"endColumn":22,"suggestions":"1843"},{"ruleId":"1814","severity":1,"message":"1815","line":1778,"column":19,"nodeType":"1816","messageId":"1817","endLine":1778,"endColumn":22,"suggestions":"1844"},{"ruleId":"1814","severity":1,"message":"1815","line":1869,"column":19,"nodeType":"1816","messageId":"1817","endLine":1869,"endColumn":22,"suggestions":"1845"},{"ruleId":"1814","severity":1,"message":"1815","line":1959,"column":19,"nodeType":"1816","messageId":"1817","endLine":1959,"endColumn":22,"suggestions":"1846"},{"ruleId":"1814","severity":1,"message":"1815","line":2049,"column":19,"nodeType":"1816","messageId":"1817","endLine":2049,"endColumn":22,"suggestions":"1847"},{"ruleId":"1814","severity":1,"message":"1815","line":2153,"column":19,"nodeType":"1816","messageId":"1817","endLine":2153,"endColumn":22,"suggestions":"1848"},{"ruleId":"1814","severity":1,"message":"1815","line":2258,"column":19,"nodeType":"1816","messageId":"1817","endLine":2258,"endColumn":22,"suggestions":"1849"},{"ruleId":"1814","severity":1,"message":"1815","line":2362,"column":19,"nodeType":"1816","messageId":"1817","endLine":2362,"endColumn":22,"suggestions":"1850"},{"ruleId":"1814","severity":1,"message":"1815","line":2466,"column":19,"nodeType":"1816","messageId":"1817","endLine":2466,"endColumn":22,"suggestions":"1851"},{"ruleId":"1814","severity":1,"message":"1815","line":3236,"column":30,"nodeType":"1816","messageId":"1817","endLine":3236,"endColumn":33,"suggestions":"1852"},{"ruleId":"1814","severity":1,"message":"1815","line":3376,"column":19,"nodeType":"1816","messageId":"1817","endLine":3376,"endColumn":22,"suggestions":"1853"},{"ruleId":"1814","severity":1,"message":"1815","line":3398,"column":19,"nodeType":"1816","messageId":"1817","endLine":3398,"endColumn":22,"suggestions":"1854"},{"ruleId":"1814","severity":1,"message":"1815","line":3420,"column":19,"nodeType":"1816","messageId":"1817","endLine":3420,"endColumn":22,"suggestions":"1855"},{"ruleId":"1814","severity":1,"message":"1815","line":3493,"column":19,"nodeType":"1816","messageId":"1817","endLine":3493,"endColumn":22,"suggestions":"1856"},{"ruleId":"1814","severity":1,"message":"1815","line":3638,"column":19,"nodeType":"1816","messageId":"1817","endLine":3638,"endColumn":22,"suggestions":"1857"},{"ruleId":"1814","severity":1,"message":"1815","line":3654,"column":23,"nodeType":"1816","messageId":"1817","endLine":3654,"endColumn":26,"suggestions":"1858"},{"ruleId":"1814","severity":1,"message":"1815","line":3654,"column":53,"nodeType":"1816","messageId":"1817","endLine":3654,"endColumn":56,"suggestions":"1859"},{"ruleId":"1814","severity":1,"message":"1815","line":3739,"column":19,"nodeType":"1816","messageId":"1817","endLine":3739,"endColumn":22,"suggestions":"1860"},{"ruleId":"1814","severity":1,"message":"1815","line":3740,"column":25,"nodeType":"1816","messageId":"1817","endLine":3740,"endColumn":28,"suggestions":"1861"},{"ruleId":"1814","severity":1,"message":"1815","line":3889,"column":19,"nodeType":"1816","messageId":"1817","endLine":3889,"endColumn":22,"suggestions":"1862"},{"ruleId":"1814","severity":1,"message":"1815","line":3890,"column":25,"nodeType":"1816","messageId":"1817","endLine":3890,"endColumn":28,"suggestions":"1863"},{"ruleId":"1814","severity":1,"message":"1815","line":3908,"column":47,"nodeType":"1816","messageId":"1817","endLine":3908,"endColumn":50,"suggestions":"1864"},{"ruleId":"1814","severity":1,"message":"1815","line":4090,"column":30,"nodeType":"1816","messageId":"1817","endLine":4090,"endColumn":33,"suggestions":"1865"},{"ruleId":"1814","severity":1,"message":"1815","line":4092,"column":30,"nodeType":"1816","messageId":"1817","endLine":4092,"endColumn":33,"suggestions":"1866"},{"ruleId":"1814","severity":1,"message":"1815","line":4255,"column":21,"nodeType":"1816","messageId":"1817","endLine":4255,"endColumn":24,"suggestions":"1867"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":34,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":37,"suggestions":"1868"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":51,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":54,"suggestions":"1869"},{"ruleId":"1814","severity":1,"message":"1815","line":7,"column":28,"nodeType":"1816","messageId":"1817","endLine":7,"endColumn":31,"suggestions":"1870"},{"ruleId":"1814","severity":1,"message":"1815","line":7,"column":45,"nodeType":"1816","messageId":"1817","endLine":7,"endColumn":48,"suggestions":"1871"},{"ruleId":"1814","severity":1,"message":"1815","line":18,"column":57,"nodeType":"1816","messageId":"1817","endLine":18,"endColumn":60,"suggestions":"1872"},{"ruleId":"1814","severity":1,"message":"1815","line":56,"column":17,"nodeType":"1816","messageId":"1817","endLine":56,"endColumn":20,"suggestions":"1873"},{"ruleId":"1814","severity":1,"message":"1815","line":46,"column":18,"nodeType":"1816","messageId":"1817","endLine":46,"endColumn":21,"suggestions":"1874"},{"ruleId":"1814","severity":1,"message":"1815","line":66,"column":52,"nodeType":"1816","messageId":"1817","endLine":66,"endColumn":55,"suggestions":"1875"},{"ruleId":"1814","severity":1,"message":"1815","line":109,"column":17,"nodeType":"1816","messageId":"1817","endLine":109,"endColumn":20,"suggestions":"1876"},{"ruleId":"1814","severity":1,"message":"1815","line":26,"column":20,"nodeType":"1816","messageId":"1817","endLine":26,"endColumn":23,"suggestions":"1877"},{"ruleId":"1814","severity":1,"message":"1815","line":51,"column":20,"nodeType":"1816","messageId":"1817","endLine":51,"endColumn":23,"suggestions":"1878"},{"ruleId":"1814","severity":1,"message":"1815","line":76,"column":20,"nodeType":"1816","messageId":"1817","endLine":76,"endColumn":23,"suggestions":"1879"},{"ruleId":"1814","severity":1,"message":"1815","line":131,"column":20,"nodeType":"1816","messageId":"1817","endLine":131,"endColumn":23,"suggestions":"1880"},{"ruleId":"1814","severity":1,"message":"1815","line":24,"column":21,"nodeType":"1816","messageId":"1817","endLine":24,"endColumn":24,"suggestions":"1881"},{"ruleId":"1814","severity":1,"message":"1815","line":30,"column":40,"nodeType":"1816","messageId":"1817","endLine":30,"endColumn":43,"suggestions":"1882"},{"ruleId":"1814","severity":1,"message":"1815","line":32,"column":36,"nodeType":"1816","messageId":"1817","endLine":32,"endColumn":39,"suggestions":"1883"},{"ruleId":"1814","severity":1,"message":"1815","line":33,"column":38,"nodeType":"1816","messageId":"1817","endLine":33,"endColumn":41,"suggestions":"1884"},{"ruleId":"1814","severity":1,"message":"1815","line":35,"column":38,"nodeType":"1816","messageId":"1817","endLine":35,"endColumn":41,"suggestions":"1885"},{"ruleId":"1814","severity":1,"message":"1815","line":37,"column":39,"nodeType":"1816","messageId":"1817","endLine":37,"endColumn":42,"suggestions":"1886"},{"ruleId":"1814","severity":1,"message":"1815","line":39,"column":44,"nodeType":"1816","messageId":"1817","endLine":39,"endColumn":47,"suggestions":"1887"},{"ruleId":"1814","severity":1,"message":"1815","line":41,"column":37,"nodeType":"1816","messageId":"1817","endLine":41,"endColumn":40,"suggestions":"1888"},{"ruleId":"1814","severity":1,"message":"1815","line":42,"column":42,"nodeType":"1816","messageId":"1817","endLine":42,"endColumn":45,"suggestions":"1889"},{"ruleId":"1814","severity":1,"message":"1815","line":44,"column":37,"nodeType":"1816","messageId":"1817","endLine":44,"endColumn":40,"suggestions":"1890"},{"ruleId":"1814","severity":1,"message":"1815","line":45,"column":39,"nodeType":"1816","messageId":"1817","endLine":45,"endColumn":42,"suggestions":"1891"},{"ruleId":"1814","severity":1,"message":"1815","line":48,"column":77,"nodeType":"1816","messageId":"1817","endLine":48,"endColumn":80,"suggestions":"1892"},{"ruleId":"1814","severity":1,"message":"1815","line":70,"column":59,"nodeType":"1816","messageId":"1817","endLine":70,"endColumn":62,"suggestions":"1893"},{"ruleId":"1814","severity":1,"message":"1815","line":77,"column":68,"nodeType":"1816","messageId":"1817","endLine":77,"endColumn":71,"suggestions":"1894"},{"ruleId":"1814","severity":1,"message":"1815","line":77,"column":80,"nodeType":"1816","messageId":"1817","endLine":77,"endColumn":83,"suggestions":"1895"},{"ruleId":"1814","severity":1,"message":"1815","line":156,"column":46,"nodeType":"1816","messageId":"1817","endLine":156,"endColumn":49,"suggestions":"1896"},{"ruleId":"1814","severity":1,"message":"1815","line":180,"column":81,"nodeType":"1816","messageId":"1817","endLine":180,"endColumn":84,"suggestions":"1897"},{"ruleId":"1814","severity":1,"message":"1815","line":246,"column":75,"nodeType":"1816","messageId":"1817","endLine":246,"endColumn":78,"suggestions":"1898"},{"ruleId":"1814","severity":1,"message":"1815","line":254,"column":52,"nodeType":"1816","messageId":"1817","endLine":254,"endColumn":55,"suggestions":"1899"},{"ruleId":"1814","severity":1,"message":"1815","line":276,"column":71,"nodeType":"1816","messageId":"1817","endLine":276,"endColumn":74,"suggestions":"1900"},{"ruleId":"1814","severity":1,"message":"1815","line":292,"column":10,"nodeType":"1816","messageId":"1817","endLine":292,"endColumn":13,"suggestions":"1901"},{"ruleId":"1814","severity":1,"message":"1815","line":314,"column":10,"nodeType":"1816","messageId":"1817","endLine":314,"endColumn":13,"suggestions":"1902"},{"ruleId":"1814","severity":1,"message":"1815","line":344,"column":81,"nodeType":"1816","messageId":"1817","endLine":344,"endColumn":84,"suggestions":"1903"},{"ruleId":"1814","severity":1,"message":"1815","line":352,"column":75,"nodeType":"1816","messageId":"1817","endLine":352,"endColumn":78,"suggestions":"1904"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":34,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":37,"suggestions":"1905"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":51,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":54,"suggestions":"1906"},{"ruleId":"1814","severity":1,"message":"1815","line":10,"column":19,"nodeType":"1816","messageId":"1817","endLine":10,"endColumn":22,"suggestions":"1907"},{"ruleId":"1814","severity":1,"message":"1815","line":110,"column":57,"nodeType":"1816","messageId":"1817","endLine":110,"endColumn":60,"suggestions":"1908"},{"ruleId":"1814","severity":1,"message":"1815","line":110,"column":62,"nodeType":"1816","messageId":"1817","endLine":110,"endColumn":65,"suggestions":"1909"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":54,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":57,"suggestions":"1910"},{"ruleId":"1814","severity":1,"message":"1815","line":20,"column":21,"nodeType":"1816","messageId":"1817","endLine":20,"endColumn":24,"suggestions":"1911"},{"ruleId":"1814","severity":1,"message":"1815","line":47,"column":21,"nodeType":"1816","messageId":"1817","endLine":47,"endColumn":24,"suggestions":"1912"},{"ruleId":"1814","severity":1,"message":"1815","line":30,"column":40,"nodeType":"1816","messageId":"1817","endLine":30,"endColumn":43,"suggestions":"1913"},{"ruleId":"1814","severity":1,"message":"1815","line":237,"column":37,"nodeType":"1816","messageId":"1817","endLine":237,"endColumn":40,"suggestions":"1914"},{"ruleId":"1814","severity":1,"message":"1815","line":7,"column":10,"nodeType":"1816","messageId":"1817","endLine":7,"endColumn":13,"suggestions":"1915"},{"ruleId":"1814","severity":1,"message":"1815","line":100,"column":17,"nodeType":"1816","messageId":"1817","endLine":100,"endColumn":20,"suggestions":"1916"},{"ruleId":"1917","severity":1,"message":"1918","line":211,"column":7,"nodeType":"1919","endLine":211,"endColumn":10},{"ruleId":"1917","severity":1,"message":"1918","line":235,"column":7,"nodeType":"1919","endLine":235,"endColumn":10},{"ruleId":"1917","severity":1,"message":"1918","line":259,"column":7,"nodeType":"1919","endLine":259,"endColumn":10},{"ruleId":"1917","severity":1,"message":"1918","line":282,"column":7,"nodeType":"1919","endLine":282,"endColumn":10},{"ruleId":"1917","severity":1,"message":"1918","line":31,"column":3,"nodeType":"1919","endLine":31,"endColumn":6},{"ruleId":"1917","severity":1,"message":"1918","line":42,"column":3,"nodeType":"1919","endLine":42,"endColumn":6},{"ruleId":"1917","severity":1,"message":"1918","line":73,"column":3,"nodeType":"1919","endLine":73,"endColumn":6},{"ruleId":"1814","severity":1,"message":"1815","line":17,"column":49,"nodeType":"1816","messageId":"1817","endLine":17,"endColumn":52,"suggestions":"1920"},{"ruleId":"1814","severity":1,"message":"1815","line":21,"column":51,"nodeType":"1816","messageId":"1817","endLine":21,"endColumn":54,"suggestions":"1921"},{"ruleId":"1814","severity":1,"message":"1815","line":30,"column":56,"nodeType":"1816","messageId":"1817","endLine":30,"endColumn":59,"suggestions":"1922"},{"ruleId":"1814","severity":1,"message":"1815","line":39,"column":52,"nodeType":"1816","messageId":"1817","endLine":39,"endColumn":55,"suggestions":"1923"},{"ruleId":"1814","severity":1,"message":"1815","line":52,"column":53,"nodeType":"1816","messageId":"1817","endLine":52,"endColumn":56,"suggestions":"1924"},{"ruleId":"1814","severity":1,"message":"1815","line":64,"column":49,"nodeType":"1816","messageId":"1817","endLine":64,"endColumn":52,"suggestions":"1925"},{"ruleId":"1814","severity":1,"message":"1815","line":100,"column":82,"nodeType":"1816","messageId":"1817","endLine":100,"endColumn":85,"suggestions":"1926"},{"ruleId":"1814","severity":1,"message":"1815","line":176,"column":82,"nodeType":"1816","messageId":"1817","endLine":176,"endColumn":85,"suggestions":"1927"},{"ruleId":"1814","severity":1,"message":"1815","line":287,"column":17,"nodeType":"1816","messageId":"1817","endLine":287,"endColumn":20,"suggestions":"1928"},{"ruleId":"1814","severity":1,"message":"1815","line":293,"column":41,"nodeType":"1816","messageId":"1817","endLine":293,"endColumn":44,"suggestions":"1929"},{"ruleId":"1814","severity":1,"message":"1815","line":337,"column":17,"nodeType":"1816","messageId":"1817","endLine":337,"endColumn":20,"suggestions":"1930"},{"ruleId":"1814","severity":1,"message":"1815","line":56,"column":17,"nodeType":"1816","messageId":"1817","endLine":56,"endColumn":20,"suggestions":"1931"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":46,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":49,"suggestions":"1932"},{"ruleId":"1814","severity":1,"message":"1815","line":9,"column":35,"nodeType":"1816","messageId":"1817","endLine":9,"endColumn":38,"suggestions":"1933"},{"ruleId":"1814","severity":1,"message":"1815","line":32,"column":36,"nodeType":"1816","messageId":"1817","endLine":32,"endColumn":39,"suggestions":"1934"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":49,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":52,"suggestions":"1935"},{"ruleId":"1814","severity":1,"message":"1815","line":7,"column":26,"nodeType":"1816","messageId":"1817","endLine":7,"endColumn":29,"suggestions":"1936"},{"ruleId":"1814","severity":1,"message":"1815","line":16,"column":44,"nodeType":"1816","messageId":"1817","endLine":16,"endColumn":47,"suggestions":"1937"},{"ruleId":"1814","severity":1,"message":"1815","line":16,"column":59,"nodeType":"1816","messageId":"1817","endLine":16,"endColumn":62,"suggestions":"1938"},{"ruleId":"1814","severity":1,"message":"1815","line":72,"column":39,"nodeType":"1816","messageId":"1817","endLine":72,"endColumn":42,"suggestions":"1939"},{"ruleId":"1814","severity":1,"message":"1815","line":72,"column":55,"nodeType":"1816","messageId":"1817","endLine":72,"endColumn":58,"suggestions":"1940"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":47,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":50,"suggestions":"1941"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":53,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":56,"suggestions":"1942"},{"ruleId":"1814","severity":1,"message":"1815","line":9,"column":42,"nodeType":"1816","messageId":"1817","endLine":9,"endColumn":45,"suggestions":"1943"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":55,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":58,"suggestions":"1944"},{"ruleId":"1814","severity":1,"message":"1815","line":32,"column":21,"nodeType":"1816","messageId":"1817","endLine":32,"endColumn":24,"suggestions":"1945"},{"ruleId":"1814","severity":1,"message":"1815","line":83,"column":17,"nodeType":"1816","messageId":"1817","endLine":83,"endColumn":20,"suggestions":"1946"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":50,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":53,"suggestions":"1947"},{"ruleId":"1814","severity":1,"message":"1815","line":9,"column":42,"nodeType":"1816","messageId":"1817","endLine":9,"endColumn":45,"suggestions":"1948"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":53,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":56,"suggestions":"1949"},{"ruleId":"1814","severity":1,"message":"1815","line":9,"column":42,"nodeType":"1816","messageId":"1817","endLine":9,"endColumn":45,"suggestions":"1950"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":47,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":50,"suggestions":"1951"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":47,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":50,"suggestions":"1952"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":53,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":56,"suggestions":"1953"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":55,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":58,"suggestions":"1954"},{"ruleId":"1814","severity":1,"message":"1815","line":32,"column":21,"nodeType":"1816","messageId":"1817","endLine":32,"endColumn":24,"suggestions":"1955"},{"ruleId":"1814","severity":1,"message":"1815","line":84,"column":17,"nodeType":"1816","messageId":"1817","endLine":84,"endColumn":20,"suggestions":"1956"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":50,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":53,"suggestions":"1957"},{"ruleId":"1814","severity":1,"message":"1815","line":9,"column":42,"nodeType":"1816","messageId":"1817","endLine":9,"endColumn":45,"suggestions":"1958"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":53,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":56,"suggestions":"1959"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":47,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":50,"suggestions":"1960"},{"ruleId":"1814","severity":1,"message":"1815","line":41,"column":37,"nodeType":"1816","messageId":"1817","endLine":41,"endColumn":40,"suggestions":"1961"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":50,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":53,"suggestions":"1962"},{"ruleId":"1814","severity":1,"message":"1815","line":12,"column":14,"nodeType":"1816","messageId":"1817","endLine":12,"endColumn":17,"suggestions":"1963"},{"ruleId":"1814","severity":1,"message":"1815","line":14,"column":40,"nodeType":"1816","messageId":"1817","endLine":14,"endColumn":43,"suggestions":"1964"},{"ruleId":"1814","severity":1,"message":"1815","line":18,"column":36,"nodeType":"1816","messageId":"1817","endLine":18,"endColumn":39,"suggestions":"1965"},{"ruleId":"1814","severity":1,"message":"1815","line":22,"column":46,"nodeType":"1816","messageId":"1817","endLine":22,"endColumn":49,"suggestions":"1966"},{"ruleId":"1814","severity":1,"message":"1815","line":34,"column":57,"nodeType":"1816","messageId":"1817","endLine":34,"endColumn":60,"suggestions":"1967"},{"ruleId":"1814","severity":1,"message":"1815","line":39,"column":10,"nodeType":"1816","messageId":"1817","endLine":39,"endColumn":13,"suggestions":"1968"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":47,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":50,"suggestions":"1969"},{"ruleId":"1814","severity":1,"message":"1815","line":7,"column":45,"nodeType":"1816","messageId":"1817","endLine":7,"endColumn":48,"suggestions":"1970"},{"ruleId":"1814","severity":1,"message":"1815","line":13,"column":50,"nodeType":"1816","messageId":"1817","endLine":13,"endColumn":53,"suggestions":"1971"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":50,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":53,"suggestions":"1972"},{"ruleId":"1814","severity":1,"message":"1815","line":15,"column":78,"nodeType":"1816","messageId":"1817","endLine":15,"endColumn":81,"suggestions":"1973"},{"ruleId":"1814","severity":1,"message":"1815","line":55,"column":61,"nodeType":"1816","messageId":"1817","endLine":55,"endColumn":64,"suggestions":"1974"},{"ruleId":"1814","severity":1,"message":"1815","line":87,"column":17,"nodeType":"1816","messageId":"1817","endLine":87,"endColumn":20,"suggestions":"1975"},{"ruleId":"1814","severity":1,"message":"1815","line":41,"column":17,"nodeType":"1816","messageId":"1817","endLine":41,"endColumn":20,"suggestions":"1976"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":36,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":39,"suggestions":"1977"},{"ruleId":"1814","severity":1,"message":"1815","line":8,"column":50,"nodeType":"1816","messageId":"1817","endLine":8,"endColumn":53,"suggestions":"1978"},{"ruleId":"1814","severity":1,"message":"1815","line":17,"column":78,"nodeType":"1816","messageId":"1817","endLine":17,"endColumn":81,"suggestions":"1979"},{"ruleId":"1814","severity":1,"message":"1815","line":57,"column":61,"nodeType":"1816","messageId":"1817","endLine":57,"endColumn":64,"suggestions":"1980"},{"ruleId":"1814","severity":1,"message":"1815","line":89,"column":47,"nodeType":"1816","messageId":"1817","endLine":89,"endColumn":50,"suggestions":"1981"},{"ruleId":"1814","severity":1,"message":"1815","line":90,"column":25,"nodeType":"1816","messageId":"1817","endLine":90,"endColumn":28,"suggestions":"1982"},{"ruleId":"1814","severity":1,"message":"1815","line":93,"column":59,"nodeType":"1816","messageId":"1817","endLine":93,"endColumn":62,"suggestions":"1983"},{"ruleId":"1814","severity":1,"message":"1815","line":94,"column":23,"nodeType":"1816","messageId":"1817","endLine":94,"endColumn":26,"suggestions":"1984"},{"ruleId":"1814","severity":1,"message":"1815","line":95,"column":17,"nodeType":"1816","messageId":"1817","endLine":95,"endColumn":20,"suggestions":"1985"},{"ruleId":"1814","severity":1,"message":"1815","line":95,"column":30,"nodeType":"1816","messageId":"1817","endLine":95,"endColumn":33,"suggestions":"1986"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":43,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":46,"suggestions":"1987"},{"ruleId":"1814","severity":1,"message":"1815","line":55,"column":31,"nodeType":"1816","messageId":"1817","endLine":55,"endColumn":34,"suggestions":"1988"},{"ruleId":"1814","severity":1,"message":"1815","line":17,"column":36,"nodeType":"1816","messageId":"1817","endLine":17,"endColumn":39,"suggestions":"1989"},{"ruleId":"1814","severity":1,"message":"1815","line":27,"column":34,"nodeType":"1816","messageId":"1817","endLine":27,"endColumn":37,"suggestions":"1990"},{"ruleId":"1814","severity":1,"message":"1815","line":44,"column":34,"nodeType":"1816","messageId":"1817","endLine":44,"endColumn":37,"suggestions":"1991"},{"ruleId":"1814","severity":1,"message":"1815","line":44,"column":57,"nodeType":"1816","messageId":"1817","endLine":44,"endColumn":60,"suggestions":"1992"},{"ruleId":"1814","severity":1,"message":"1815","line":53,"column":31,"nodeType":"1816","messageId":"1817","endLine":53,"endColumn":34,"suggestions":"1993"},{"ruleId":"1814","severity":1,"message":"1815","line":72,"column":18,"nodeType":"1816","messageId":"1817","endLine":72,"endColumn":21,"suggestions":"1994"},{"ruleId":"1814","severity":1,"message":"1815","line":100,"column":33,"nodeType":"1816","messageId":"1817","endLine":100,"endColumn":36,"suggestions":"1995"},{"ruleId":"1814","severity":1,"message":"1815","line":108,"column":51,"nodeType":"1816","messageId":"1817","endLine":108,"endColumn":54,"suggestions":"1996"},{"ruleId":"1814","severity":1,"message":"1815","line":10,"column":25,"nodeType":"1816","messageId":"1817","endLine":10,"endColumn":28,"suggestions":"1997"},{"ruleId":"1814","severity":1,"message":"1815","line":89,"column":24,"nodeType":"1816","messageId":"1817","endLine":89,"endColumn":27,"suggestions":"1998"},{"ruleId":"1814","severity":1,"message":"1815","line":104,"column":28,"nodeType":"1816","messageId":"1817","endLine":104,"endColumn":31,"suggestions":"1999"},{"ruleId":"1814","severity":1,"message":"1815","line":109,"column":24,"nodeType":"1816","messageId":"1817","endLine":109,"endColumn":27,"suggestions":"2000"},{"ruleId":"1814","severity":1,"message":"1815","line":114,"column":26,"nodeType":"1816","messageId":"1817","endLine":114,"endColumn":29,"suggestions":"2001"},{"ruleId":"1814","severity":1,"message":"1815","line":119,"column":25,"nodeType":"1816","messageId":"1817","endLine":119,"endColumn":28,"suggestions":"2002"},{"ruleId":"1814","severity":1,"message":"1815","line":129,"column":26,"nodeType":"1816","messageId":"1817","endLine":129,"endColumn":29,"suggestions":"2003"},{"ruleId":"1814","severity":1,"message":"1815","line":262,"column":41,"nodeType":"1816","messageId":"1817","endLine":262,"endColumn":44,"suggestions":"2004"},{"ruleId":"1814","severity":1,"message":"1815","line":305,"column":16,"nodeType":"1816","messageId":"1817","endLine":305,"endColumn":19,"suggestions":"2005"},{"ruleId":"1814","severity":1,"message":"1815","line":318,"column":16,"nodeType":"1816","messageId":"1817","endLine":318,"endColumn":19,"suggestions":"2006"},{"ruleId":"1814","severity":1,"message":"1815","line":322,"column":18,"nodeType":"1816","messageId":"1817","endLine":322,"endColumn":21,"suggestions":"2007"},{"ruleId":"1814","severity":1,"message":"1815","line":323,"column":18,"nodeType":"1816","messageId":"1817","endLine":323,"endColumn":21,"suggestions":"2008"},{"ruleId":"1814","severity":1,"message":"1815","line":330,"column":35,"nodeType":"1816","messageId":"1817","endLine":330,"endColumn":38,"suggestions":"2009"},{"ruleId":"1814","severity":1,"message":"1815","line":420,"column":20,"nodeType":"1816","messageId":"1817","endLine":420,"endColumn":23,"suggestions":"2010"},{"ruleId":"1814","severity":1,"message":"1815","line":422,"column":22,"nodeType":"1816","messageId":"1817","endLine":422,"endColumn":25,"suggestions":"2011"},{"ruleId":"1814","severity":1,"message":"1815","line":423,"column":22,"nodeType":"1816","messageId":"1817","endLine":423,"endColumn":25,"suggestions":"2012"},{"ruleId":"1814","severity":1,"message":"1815","line":442,"column":31,"nodeType":"1816","messageId":"1817","endLine":442,"endColumn":34,"suggestions":"2013"},{"ruleId":"1814","severity":1,"message":"1815","line":445,"column":19,"nodeType":"1816","messageId":"1817","endLine":445,"endColumn":22,"suggestions":"2014"},{"ruleId":"1814","severity":1,"message":"1815","line":449,"column":44,"nodeType":"1816","messageId":"1817","endLine":449,"endColumn":47,"suggestions":"2015"},{"ruleId":"1814","severity":1,"message":"1815","line":461,"column":31,"nodeType":"1816","messageId":"1817","endLine":461,"endColumn":34,"suggestions":"2016"},{"ruleId":"1814","severity":1,"message":"1815","line":461,"column":43,"nodeType":"1816","messageId":"1817","endLine":461,"endColumn":46,"suggestions":"2017"},{"ruleId":"1814","severity":1,"message":"1815","line":465,"column":46,"nodeType":"1816","messageId":"1817","endLine":465,"endColumn":49,"suggestions":"2018"},{"ruleId":"1814","severity":1,"message":"1815","line":467,"column":44,"nodeType":"1816","messageId":"1817","endLine":467,"endColumn":47,"suggestions":"2019"},{"ruleId":"1814","severity":1,"message":"1815","line":479,"column":29,"nodeType":"1816","messageId":"1817","endLine":479,"endColumn":32,"suggestions":"2020"},{"ruleId":"1814","severity":1,"message":"1815","line":479,"column":41,"nodeType":"1816","messageId":"1817","endLine":479,"endColumn":44,"suggestions":"2021"},{"ruleId":"1814","severity":1,"message":"1815","line":482,"column":29,"nodeType":"1816","messageId":"1817","endLine":482,"endColumn":32,"suggestions":"2022"},{"ruleId":"1814","severity":1,"message":"1815","line":483,"column":27,"nodeType":"1816","messageId":"1817","endLine":483,"endColumn":30,"suggestions":"2023"},{"ruleId":"1814","severity":1,"message":"1815","line":483,"column":48,"nodeType":"1816","messageId":"1817","endLine":483,"endColumn":51,"suggestions":"2024"},{"ruleId":"1814","severity":1,"message":"1815","line":483,"column":70,"nodeType":"1816","messageId":"1817","endLine":483,"endColumn":73,"suggestions":"2025"},{"ruleId":"1814","severity":1,"message":"1815","line":484,"column":19,"nodeType":"1816","messageId":"1817","endLine":484,"endColumn":22,"suggestions":"2026"},{"ruleId":"1814","severity":1,"message":"1815","line":500,"column":30,"nodeType":"1816","messageId":"1817","endLine":500,"endColumn":33,"suggestions":"2027"},{"ruleId":"1814","severity":1,"message":"1815","line":500,"column":42,"nodeType":"1816","messageId":"1817","endLine":500,"endColumn":45,"suggestions":"2028"},{"ruleId":"1814","severity":1,"message":"1815","line":504,"column":42,"nodeType":"1816","messageId":"1817","endLine":504,"endColumn":45,"suggestions":"2029"},{"ruleId":"1814","severity":1,"message":"1815","line":511,"column":19,"nodeType":"1816","messageId":"1817","endLine":511,"endColumn":22,"suggestions":"2030"},{"ruleId":"1814","severity":1,"message":"1815","line":515,"column":24,"nodeType":"1816","messageId":"1817","endLine":515,"endColumn":27,"suggestions":"2031"},{"ruleId":"1814","severity":1,"message":"1815","line":538,"column":66,"nodeType":"1816","messageId":"1817","endLine":538,"endColumn":69,"suggestions":"2032"},{"ruleId":"1814","severity":1,"message":"1815","line":538,"column":78,"nodeType":"1816","messageId":"1817","endLine":538,"endColumn":81,"suggestions":"2033"},{"ruleId":"1814","severity":1,"message":"1815","line":556,"column":23,"nodeType":"1816","messageId":"1817","endLine":556,"endColumn":26,"suggestions":"2034"},{"ruleId":"1814","severity":1,"message":"1815","line":556,"column":35,"nodeType":"1816","messageId":"1817","endLine":556,"endColumn":38,"suggestions":"2035"},{"ruleId":"1814","severity":1,"message":"1815","line":588,"column":22,"nodeType":"1816","messageId":"1817","endLine":588,"endColumn":25,"suggestions":"2036"},{"ruleId":"1814","severity":1,"message":"1815","line":588,"column":34,"nodeType":"1816","messageId":"1817","endLine":588,"endColumn":37,"suggestions":"2037"},{"ruleId":"1814","severity":1,"message":"1815","line":603,"column":24,"nodeType":"1816","messageId":"1817","endLine":603,"endColumn":27,"suggestions":"2038"},{"ruleId":"1814","severity":1,"message":"1815","line":620,"column":31,"nodeType":"1816","messageId":"1817","endLine":620,"endColumn":34,"suggestions":"2039"},{"ruleId":"1814","severity":1,"message":"1815","line":620,"column":43,"nodeType":"1816","messageId":"1817","endLine":620,"endColumn":46,"suggestions":"2040"},{"ruleId":"1814","severity":1,"message":"1815","line":623,"column":46,"nodeType":"1816","messageId":"1817","endLine":623,"endColumn":49,"suggestions":"2041"},{"ruleId":"1814","severity":1,"message":"1815","line":641,"column":19,"nodeType":"1816","messageId":"1817","endLine":641,"endColumn":22,"suggestions":"2042"},{"ruleId":"1814","severity":1,"message":"1815","line":674,"column":19,"nodeType":"1816","messageId":"1817","endLine":674,"endColumn":22,"suggestions":"2043"},{"ruleId":"1814","severity":1,"message":"1815","line":674,"column":31,"nodeType":"1816","messageId":"1817","endLine":674,"endColumn":34,"suggestions":"2044"},{"ruleId":"1814","severity":1,"message":"1815","line":684,"column":21,"nodeType":"1816","messageId":"1817","endLine":684,"endColumn":24,"suggestions":"2045"},{"ruleId":"1814","severity":1,"message":"1815","line":701,"column":20,"nodeType":"1816","messageId":"1817","endLine":701,"endColumn":23,"suggestions":"2046"},{"ruleId":"1814","severity":1,"message":"1815","line":719,"column":20,"nodeType":"1816","messageId":"1817","endLine":719,"endColumn":23,"suggestions":"2047"},{"ruleId":"1814","severity":1,"message":"1815","line":719,"column":32,"nodeType":"1816","messageId":"1817","endLine":719,"endColumn":35,"suggestions":"2048"},{"ruleId":"1814","severity":1,"message":"1815","line":720,"column":62,"nodeType":"1816","messageId":"1817","endLine":720,"endColumn":65,"suggestions":"2049"},{"ruleId":"1814","severity":1,"message":"1815","line":735,"column":44,"nodeType":"1816","messageId":"1817","endLine":735,"endColumn":47,"suggestions":"2050"},{"ruleId":"1814","severity":1,"message":"1815","line":744,"column":32,"nodeType":"1816","messageId":"1817","endLine":744,"endColumn":35,"suggestions":"2051"},{"ruleId":"1814","severity":1,"message":"1815","line":799,"column":19,"nodeType":"1816","messageId":"1817","endLine":799,"endColumn":22,"suggestions":"2052"},{"ruleId":"1814","severity":1,"message":"1815","line":799,"column":31,"nodeType":"1816","messageId":"1817","endLine":799,"endColumn":34,"suggestions":"2053"},{"ruleId":"1814","severity":1,"message":"1815","line":816,"column":21,"nodeType":"1816","messageId":"1817","endLine":816,"endColumn":24,"suggestions":"2054"},{"ruleId":"1814","severity":1,"message":"1815","line":834,"column":21,"nodeType":"1816","messageId":"1817","endLine":834,"endColumn":24,"suggestions":"2055"},{"ruleId":"1814","severity":1,"message":"1815","line":834,"column":33,"nodeType":"1816","messageId":"1817","endLine":834,"endColumn":36,"suggestions":"2056"},{"ruleId":"1814","severity":1,"message":"1815","line":852,"column":26,"nodeType":"1816","messageId":"1817","endLine":852,"endColumn":29,"suggestions":"2057"},{"ruleId":"1814","severity":1,"message":"1815","line":852,"column":38,"nodeType":"1816","messageId":"1817","endLine":852,"endColumn":41,"suggestions":"2058"},{"ruleId":"1814","severity":1,"message":"1815","line":853,"column":67,"nodeType":"1816","messageId":"1817","endLine":853,"endColumn":70,"suggestions":"2059"},{"ruleId":"1814","severity":1,"message":"1815","line":892,"column":25,"nodeType":"1816","messageId":"1817","endLine":892,"endColumn":28,"suggestions":"2060"},{"ruleId":"1814","severity":1,"message":"1815","line":892,"column":37,"nodeType":"1816","messageId":"1817","endLine":892,"endColumn":40,"suggestions":"2061"},{"ruleId":"1814","severity":1,"message":"1815","line":905,"column":27,"nodeType":"1816","messageId":"1817","endLine":905,"endColumn":30,"suggestions":"2062"},{"ruleId":"1814","severity":1,"message":"1815","line":929,"column":27,"nodeType":"1816","messageId":"1817","endLine":929,"endColumn":30,"suggestions":"2063"},{"ruleId":"1814","severity":1,"message":"1815","line":929,"column":39,"nodeType":"1816","messageId":"1817","endLine":929,"endColumn":42,"suggestions":"2064"},{"ruleId":"1814","severity":1,"message":"1815","line":947,"column":22,"nodeType":"1816","messageId":"1817","endLine":947,"endColumn":25,"suggestions":"2065"},{"ruleId":"1814","severity":1,"message":"1815","line":947,"column":34,"nodeType":"1816","messageId":"1817","endLine":947,"endColumn":37,"suggestions":"2066"},{"ruleId":"1814","severity":1,"message":"1815","line":991,"column":21,"nodeType":"1816","messageId":"1817","endLine":991,"endColumn":24,"suggestions":"2067"},{"ruleId":"1814","severity":1,"message":"1815","line":991,"column":33,"nodeType":"1816","messageId":"1817","endLine":991,"endColumn":36,"suggestions":"2068"},{"ruleId":"1814","severity":1,"message":"1815","line":1008,"column":23,"nodeType":"1816","messageId":"1817","endLine":1008,"endColumn":26,"suggestions":"2069"},{"ruleId":"1814","severity":1,"message":"1815","line":1026,"column":23,"nodeType":"1816","messageId":"1817","endLine":1026,"endColumn":26,"suggestions":"2070"},{"ruleId":"1814","severity":1,"message":"1815","line":1026,"column":35,"nodeType":"1816","messageId":"1817","endLine":1026,"endColumn":38,"suggestions":"2071"},{"ruleId":"1814","severity":1,"message":"1815","line":1086,"column":48,"nodeType":"1816","messageId":"1817","endLine":1086,"endColumn":51,"suggestions":"2072"},{"ruleId":"1814","severity":1,"message":"1815","line":1111,"column":42,"nodeType":"1816","messageId":"1817","endLine":1111,"endColumn":45,"suggestions":"2073"},{"ruleId":"1814","severity":1,"message":"1815","line":1123,"column":25,"nodeType":"1816","messageId":"1817","endLine":1123,"endColumn":28,"suggestions":"2074"},{"ruleId":"1814","severity":1,"message":"1815","line":1154,"column":22,"nodeType":"1816","messageId":"1817","endLine":1154,"endColumn":25,"suggestions":"2075"},{"ruleId":"1814","severity":1,"message":"1815","line":1166,"column":19,"nodeType":"1816","messageId":"1817","endLine":1166,"endColumn":22,"suggestions":"2076"},{"ruleId":"1814","severity":1,"message":"1815","line":1166,"column":34,"nodeType":"1816","messageId":"1817","endLine":1166,"endColumn":37,"suggestions":"2077"},{"ruleId":"1814","severity":1,"message":"1815","line":1177,"column":24,"nodeType":"1816","messageId":"1817","endLine":1177,"endColumn":27,"suggestions":"2078"},{"ruleId":"1814","severity":1,"message":"1815","line":1177,"column":56,"nodeType":"1816","messageId":"1817","endLine":1177,"endColumn":59,"suggestions":"2079"},{"ruleId":"1814","severity":1,"message":"1815","line":1206,"column":24,"nodeType":"1816","messageId":"1817","endLine":1206,"endColumn":27,"suggestions":"2080"},{"ruleId":"1814","severity":1,"message":"1815","line":1213,"column":43,"nodeType":"1816","messageId":"1817","endLine":1213,"endColumn":46,"suggestions":"2081"},{"ruleId":"1814","severity":1,"message":"1815","line":1232,"column":23,"nodeType":"1816","messageId":"1817","endLine":1232,"endColumn":26,"suggestions":"2082"},{"ruleId":"1814","severity":1,"message":"1815","line":1253,"column":26,"nodeType":"1816","messageId":"1817","endLine":1253,"endColumn":29,"suggestions":"2083"},{"ruleId":"1814","severity":1,"message":"1815","line":1253,"column":38,"nodeType":"1816","messageId":"1817","endLine":1253,"endColumn":41,"suggestions":"2084"},{"ruleId":"1814","severity":1,"message":"1815","line":1253,"column":56,"nodeType":"1816","messageId":"1817","endLine":1253,"endColumn":59,"suggestions":"2085"},{"ruleId":"1814","severity":1,"message":"1815","line":1261,"column":23,"nodeType":"1816","messageId":"1817","endLine":1261,"endColumn":26,"suggestions":"2086"},{"ruleId":"1814","severity":1,"message":"1815","line":1266,"column":22,"nodeType":"1816","messageId":"1817","endLine":1266,"endColumn":25,"suggestions":"2087"},{"ruleId":"1814","severity":1,"message":"1815","line":1272,"column":20,"nodeType":"1816","messageId":"1817","endLine":1272,"endColumn":23,"suggestions":"2088"},{"ruleId":"1814","severity":1,"message":"1815","line":1311,"column":52,"nodeType":"1816","messageId":"1817","endLine":1311,"endColumn":55,"suggestions":"2089"},{"ruleId":"1814","severity":1,"message":"1815","line":1375,"column":43,"nodeType":"1816","messageId":"1817","endLine":1375,"endColumn":46,"suggestions":"2090"},{"ruleId":"1814","severity":1,"message":"1815","line":1387,"column":25,"nodeType":"1816","messageId":"1817","endLine":1387,"endColumn":28,"suggestions":"2091"},{"ruleId":"1814","severity":1,"message":"1815","line":1387,"column":45,"nodeType":"1816","messageId":"1817","endLine":1387,"endColumn":48,"suggestions":"2092"},{"ruleId":"1814","severity":1,"message":"1815","line":1389,"column":32,"nodeType":"1816","messageId":"1817","endLine":1389,"endColumn":35,"suggestions":"2093"},{"ruleId":"1814","severity":1,"message":"1815","line":1401,"column":13,"nodeType":"1816","messageId":"1817","endLine":1401,"endColumn":16,"suggestions":"2094"},{"ruleId":"1814","severity":1,"message":"1815","line":1404,"column":14,"nodeType":"1816","messageId":"1817","endLine":1404,"endColumn":17,"suggestions":"2095"},{"ruleId":"1814","severity":1,"message":"1815","line":1405,"column":12,"nodeType":"1816","messageId":"1817","endLine":1405,"endColumn":15,"suggestions":"2096"},{"ruleId":"1814","severity":1,"message":"1815","line":1406,"column":12,"nodeType":"1816","messageId":"1817","endLine":1406,"endColumn":15,"suggestions":"2097"},{"ruleId":"1814","severity":1,"message":"1815","line":1413,"column":24,"nodeType":"1816","messageId":"1817","endLine":1413,"endColumn":27,"suggestions":"2098"},{"ruleId":"1814","severity":1,"message":"1815","line":1430,"column":50,"nodeType":"1816","messageId":"1817","endLine":1430,"endColumn":53,"suggestions":"2099"},{"ruleId":"1814","severity":1,"message":"1815","line":1430,"column":62,"nodeType":"1816","messageId":"1817","endLine":1430,"endColumn":65,"suggestions":"2100"},{"ruleId":"1814","severity":1,"message":"1815","line":1430,"column":74,"nodeType":"1816","messageId":"1817","endLine":1430,"endColumn":77,"suggestions":"2101"},{"ruleId":"1814","severity":1,"message":"1815","line":1433,"column":69,"nodeType":"1816","messageId":"1817","endLine":1433,"endColumn":72,"suggestions":"2102"},{"ruleId":"1814","severity":1,"message":"1815","line":1468,"column":13,"nodeType":"1816","messageId":"1817","endLine":1468,"endColumn":16,"suggestions":"2103"},{"ruleId":"1814","severity":1,"message":"1815","line":1472,"column":12,"nodeType":"1816","messageId":"1817","endLine":1472,"endColumn":15,"suggestions":"2104"},{"ruleId":"1814","severity":1,"message":"1815","line":1473,"column":12,"nodeType":"1816","messageId":"1817","endLine":1473,"endColumn":15,"suggestions":"2105"},{"ruleId":"1814","severity":1,"message":"1815","line":1492,"column":63,"nodeType":"1816","messageId":"1817","endLine":1492,"endColumn":66,"suggestions":"2106"},{"ruleId":"1814","severity":1,"message":"1815","line":1530,"column":40,"nodeType":"1816","messageId":"1817","endLine":1530,"endColumn":43,"suggestions":"2107"},{"ruleId":"1814","severity":1,"message":"1815","line":1530,"column":52,"nodeType":"1816","messageId":"1817","endLine":1530,"endColumn":55,"suggestions":"2108"},{"ruleId":"1814","severity":1,"message":"1815","line":1530,"column":66,"nodeType":"1816","messageId":"1817","endLine":1530,"endColumn":69,"suggestions":"2109"},{"ruleId":"1814","severity":1,"message":"1815","line":1530,"column":78,"nodeType":"1816","messageId":"1817","endLine":1530,"endColumn":81,"suggestions":"2110"},{"ruleId":"1814","severity":1,"message":"1815","line":1572,"column":22,"nodeType":"1816","messageId":"1817","endLine":1572,"endColumn":25,"suggestions":"2111"},{"ruleId":"1814","severity":1,"message":"1815","line":1573,"column":38,"nodeType":"1816","messageId":"1817","endLine":1573,"endColumn":41,"suggestions":"2112"},{"ruleId":"1814","severity":1,"message":"1815","line":1577,"column":18,"nodeType":"1816","messageId":"1817","endLine":1577,"endColumn":21,"suggestions":"2113"},{"ruleId":"1814","severity":1,"message":"1815","line":1599,"column":24,"nodeType":"1816","messageId":"1817","endLine":1599,"endColumn":27,"suggestions":"2114"},{"ruleId":"1814","severity":1,"message":"1815","line":1619,"column":26,"nodeType":"1816","messageId":"1817","endLine":1619,"endColumn":29,"suggestions":"2115"},{"ruleId":"1814","severity":1,"message":"1815","line":1664,"column":40,"nodeType":"1816","messageId":"1817","endLine":1664,"endColumn":43,"suggestions":"2116"},{"ruleId":"1814","severity":1,"message":"1815","line":1671,"column":26,"nodeType":"1816","messageId":"1817","endLine":1671,"endColumn":29,"suggestions":"2117"},{"ruleId":"1814","severity":1,"message":"1815","line":1672,"column":26,"nodeType":"1816","messageId":"1817","endLine":1672,"endColumn":29,"suggestions":"2118"},{"ruleId":"1814","severity":1,"message":"1815","line":1674,"column":24,"nodeType":"1816","messageId":"1817","endLine":1674,"endColumn":27,"suggestions":"2119"},{"ruleId":"1814","severity":1,"message":"1815","line":1681,"column":26,"nodeType":"1816","messageId":"1817","endLine":1681,"endColumn":29,"suggestions":"2120"},{"ruleId":"1814","severity":1,"message":"1815","line":1682,"column":43,"nodeType":"1816","messageId":"1817","endLine":1682,"endColumn":46,"suggestions":"2121"},{"ruleId":"1814","severity":1,"message":"1815","line":1682,"column":53,"nodeType":"1816","messageId":"1817","endLine":1682,"endColumn":56,"suggestions":"2122"},{"ruleId":"1814","severity":1,"message":"1815","line":1693,"column":22,"nodeType":"1816","messageId":"1817","endLine":1693,"endColumn":25,"suggestions":"2123"},{"ruleId":"1814","severity":1,"message":"1815","line":1705,"column":20,"nodeType":"1816","messageId":"1817","endLine":1705,"endColumn":23,"suggestions":"2124"},{"ruleId":"1814","severity":1,"message":"1815","line":1772,"column":26,"nodeType":"1816","messageId":"1817","endLine":1772,"endColumn":29,"suggestions":"2125"},{"ruleId":"1814","severity":1,"message":"1815","line":1772,"column":42,"nodeType":"1816","messageId":"1817","endLine":1772,"endColumn":45,"suggestions":"2126"},{"ruleId":"1814","severity":1,"message":"1815","line":1791,"column":27,"nodeType":"1816","messageId":"1817","endLine":1791,"endColumn":30,"suggestions":"2127"},{"ruleId":"1814","severity":1,"message":"1815","line":1803,"column":27,"nodeType":"1816","messageId":"1817","endLine":1803,"endColumn":30,"suggestions":"2128"},{"ruleId":"1814","severity":1,"message":"1815","line":1819,"column":29,"nodeType":"1816","messageId":"1817","endLine":1819,"endColumn":32,"suggestions":"2129"},{"ruleId":"1814","severity":1,"message":"1815","line":1842,"column":27,"nodeType":"1816","messageId":"1817","endLine":1842,"endColumn":30,"suggestions":"2130"},{"ruleId":"1814","severity":1,"message":"1815","line":1855,"column":24,"nodeType":"1816","messageId":"1817","endLine":1855,"endColumn":27,"suggestions":"2131"},{"ruleId":"1814","severity":1,"message":"1815","line":1855,"column":35,"nodeType":"1816","messageId":"1817","endLine":1855,"endColumn":38,"suggestions":"2132"},{"ruleId":"1814","severity":1,"message":"1815","line":1870,"column":29,"nodeType":"1816","messageId":"1817","endLine":1870,"endColumn":32,"suggestions":"2133"},{"ruleId":"1814","severity":1,"message":"1815","line":1877,"column":27,"nodeType":"1816","messageId":"1817","endLine":1877,"endColumn":30,"suggestions":"2134"},{"ruleId":"1814","severity":1,"message":"1815","line":1892,"column":28,"nodeType":"1816","messageId":"1817","endLine":1892,"endColumn":31,"suggestions":"2135"},{"ruleId":"1814","severity":1,"message":"1815","line":1901,"column":27,"nodeType":"1816","messageId":"1817","endLine":1901,"endColumn":30,"suggestions":"2136"},{"ruleId":"1814","severity":1,"message":"1815","line":2035,"column":30,"nodeType":"1816","messageId":"1817","endLine":2035,"endColumn":33,"suggestions":"2137"},{"ruleId":"1814","severity":1,"message":"1815","line":2046,"column":32,"nodeType":"1816","messageId":"1817","endLine":2046,"endColumn":35,"suggestions":"2138"},{"ruleId":"1814","severity":1,"message":"1815","line":2059,"column":31,"nodeType":"1816","messageId":"1817","endLine":2059,"endColumn":34,"suggestions":"2139"},{"ruleId":"1814","severity":1,"message":"1815","line":2059,"column":45,"nodeType":"1816","messageId":"1817","endLine":2059,"endColumn":48,"suggestions":"2140"},{"ruleId":"1814","severity":1,"message":"1815","line":2087,"column":18,"nodeType":"1816","messageId":"1817","endLine":2087,"endColumn":21,"suggestions":"2141"},{"ruleId":"1814","severity":1,"message":"1815","line":2102,"column":26,"nodeType":"1816","messageId":"1817","endLine":2102,"endColumn":29,"suggestions":"2142"},{"ruleId":"1814","severity":1,"message":"1815","line":2102,"column":40,"nodeType":"1816","messageId":"1817","endLine":2102,"endColumn":43,"suggestions":"2143"},{"ruleId":"1814","severity":1,"message":"1815","line":2116,"column":31,"nodeType":"1816","messageId":"1817","endLine":2116,"endColumn":34,"suggestions":"2144"},{"ruleId":"1814","severity":1,"message":"1815","line":2123,"column":29,"nodeType":"1816","messageId":"1817","endLine":2123,"endColumn":32,"suggestions":"2145"},{"ruleId":"1814","severity":1,"message":"1815","line":2150,"column":22,"nodeType":"1816","messageId":"1817","endLine":2150,"endColumn":25,"suggestions":"2146"},{"ruleId":"1814","severity":1,"message":"1815","line":2183,"column":35,"nodeType":"1816","messageId":"1817","endLine":2183,"endColumn":38,"suggestions":"2147"},{"ruleId":"1814","severity":1,"message":"1815","line":2238,"column":28,"nodeType":"1816","messageId":"1817","endLine":2238,"endColumn":31,"suggestions":"2148"},{"ruleId":"1814","severity":1,"message":"1815","line":2286,"column":28,"nodeType":"1816","messageId":"1817","endLine":2286,"endColumn":31,"suggestions":"2149"},{"ruleId":"1814","severity":1,"message":"1815","line":2303,"column":29,"nodeType":"1816","messageId":"1817","endLine":2303,"endColumn":32,"suggestions":"2150"},{"ruleId":"1814","severity":1,"message":"1815","line":2309,"column":29,"nodeType":"1816","messageId":"1817","endLine":2309,"endColumn":32,"suggestions":"2151"},{"ruleId":"1814","severity":1,"message":"1815","line":2313,"column":28,"nodeType":"1816","messageId":"1817","endLine":2313,"endColumn":31,"suggestions":"2152"},{"ruleId":"1814","severity":1,"message":"1815","line":2325,"column":24,"nodeType":"1816","messageId":"1817","endLine":2325,"endColumn":27,"suggestions":"2153"},{"ruleId":"1814","severity":1,"message":"1815","line":2338,"column":41,"nodeType":"1816","messageId":"1817","endLine":2338,"endColumn":44,"suggestions":"2154"},{"ruleId":"1814","severity":1,"message":"1815","line":2376,"column":30,"nodeType":"1816","messageId":"1817","endLine":2376,"endColumn":33,"suggestions":"2155"},{"ruleId":"1814","severity":1,"message":"1815","line":2385,"column":27,"nodeType":"1816","messageId":"1817","endLine":2385,"endColumn":30,"suggestions":"2156"},{"ruleId":"1814","severity":1,"message":"1815","line":2388,"column":20,"nodeType":"1816","messageId":"1817","endLine":2388,"endColumn":23,"suggestions":"2157"},{"ruleId":"1814","severity":1,"message":"1815","line":2397,"column":27,"nodeType":"1816","messageId":"1817","endLine":2397,"endColumn":30,"suggestions":"2158"},{"ruleId":"1814","severity":1,"message":"1815","line":2398,"column":22,"nodeType":"1816","messageId":"1817","endLine":2398,"endColumn":25,"suggestions":"2159"},{"ruleId":"1814","severity":1,"message":"1815","line":2491,"column":34,"nodeType":"1816","messageId":"1817","endLine":2491,"endColumn":37,"suggestions":"2160"},{"ruleId":"1814","severity":1,"message":"1815","line":2494,"column":32,"nodeType":"1816","messageId":"1817","endLine":2494,"endColumn":35,"suggestions":"2161"},{"ruleId":"1814","severity":1,"message":"1815","line":2495,"column":33,"nodeType":"1816","messageId":"1817","endLine":2495,"endColumn":36,"suggestions":"2162"},{"ruleId":"1814","severity":1,"message":"1815","line":2496,"column":39,"nodeType":"1816","messageId":"1817","endLine":2496,"endColumn":42,"suggestions":"2163"},{"ruleId":"1814","severity":1,"message":"1815","line":10,"column":12,"nodeType":"1816","messageId":"1817","endLine":10,"endColumn":15,"suggestions":"2164"},{"ruleId":"1814","severity":1,"message":"1815","line":20,"column":12,"nodeType":"1816","messageId":"1817","endLine":20,"endColumn":15,"suggestions":"2165"},{"ruleId":"1814","severity":1,"message":"1815","line":60,"column":25,"nodeType":"1816","messageId":"1817","endLine":60,"endColumn":28,"suggestions":"2166"},{"ruleId":"1814","severity":1,"message":"1815","line":120,"column":31,"nodeType":"1816","messageId":"1817","endLine":120,"endColumn":34,"suggestions":"2167"},{"ruleId":"1814","severity":1,"message":"1815","line":120,"column":45,"nodeType":"1816","messageId":"1817","endLine":120,"endColumn":48,"suggestions":"2168"},{"ruleId":"1814","severity":1,"message":"1815","line":123,"column":21,"nodeType":"1816","messageId":"1817","endLine":123,"endColumn":24,"suggestions":"2169"},{"ruleId":"1814","severity":1,"message":"1815","line":133,"column":30,"nodeType":"1816","messageId":"1817","endLine":133,"endColumn":33,"suggestions":"2170"},{"ruleId":"1814","severity":1,"message":"1815","line":133,"column":44,"nodeType":"1816","messageId":"1817","endLine":133,"endColumn":47,"suggestions":"2171"},{"ruleId":"1814","severity":1,"message":"1815","line":134,"column":32,"nodeType":"1816","messageId":"1817","endLine":134,"endColumn":35,"suggestions":"2172"},{"ruleId":"1814","severity":1,"message":"1815","line":134,"column":38,"nodeType":"1816","messageId":"1817","endLine":134,"endColumn":41,"suggestions":"2173"},{"ruleId":"1814","severity":1,"message":"1815","line":141,"column":42,"nodeType":"1816","messageId":"1817","endLine":141,"endColumn":45,"suggestions":"2174"},{"ruleId":"1814","severity":1,"message":"1815","line":161,"column":32,"nodeType":"1816","messageId":"1817","endLine":161,"endColumn":35,"suggestions":"2175"},{"ruleId":"1814","severity":1,"message":"1815","line":161,"column":44,"nodeType":"1816","messageId":"1817","endLine":161,"endColumn":47,"suggestions":"2176"},{"ruleId":"1814","severity":1,"message":"1815","line":161,"column":58,"nodeType":"1816","messageId":"1817","endLine":161,"endColumn":61,"suggestions":"2177"},{"ruleId":"1814","severity":1,"message":"1815","line":163,"column":38,"nodeType":"1816","messageId":"1817","endLine":163,"endColumn":41,"suggestions":"2178"},{"ruleId":"1814","severity":1,"message":"1815","line":17,"column":30,"nodeType":"1816","messageId":"1817","endLine":17,"endColumn":33,"suggestions":"2179"},{"ruleId":"1814","severity":1,"message":"1815","line":28,"column":32,"nodeType":"1816","messageId":"1817","endLine":28,"endColumn":35,"suggestions":"2180"},{"ruleId":"1814","severity":1,"message":"1815","line":28,"column":47,"nodeType":"1816","messageId":"1817","endLine":28,"endColumn":50,"suggestions":"2181"},{"ruleId":"2182","severity":1,"message":"2183","line":32,"column":5,"nodeType":"1919","endLine":32,"endColumn":15},{"ruleId":"1814","severity":1,"message":"1815","line":38,"column":22,"nodeType":"1816","messageId":"1817","endLine":38,"endColumn":25,"suggestions":"2184"},{"ruleId":"1814","severity":1,"message":"1815","line":44,"column":23,"nodeType":"1816","messageId":"1817","endLine":44,"endColumn":26,"suggestions":"2185"},{"ruleId":"1814","severity":1,"message":"1815","line":60,"column":22,"nodeType":"1816","messageId":"1817","endLine":60,"endColumn":25,"suggestions":"2186"},{"ruleId":"1814","severity":1,"message":"1815","line":324,"column":15,"nodeType":"1816","messageId":"1817","endLine":324,"endColumn":18,"suggestions":"2187"},{"ruleId":"1814","severity":1,"message":"1815","line":365,"column":15,"nodeType":"1816","messageId":"1817","endLine":365,"endColumn":18,"suggestions":"2188"},{"ruleId":"1814","severity":1,"message":"1815","line":406,"column":15,"nodeType":"1816","messageId":"1817","endLine":406,"endColumn":18,"suggestions":"2189"},{"ruleId":"1814","severity":1,"message":"1815","line":458,"column":22,"nodeType":"1816","messageId":"1817","endLine":458,"endColumn":25,"suggestions":"2190"},{"ruleId":"1814","severity":1,"message":"1815","line":486,"column":15,"nodeType":"1816","messageId":"1817","endLine":486,"endColumn":18,"suggestions":"2191"},{"ruleId":"1814","severity":1,"message":"1815","line":523,"column":17,"nodeType":"1816","messageId":"1817","endLine":523,"endColumn":20,"suggestions":"2192"},{"ruleId":"1814","severity":1,"message":"1815","line":563,"column":51,"nodeType":"1816","messageId":"1817","endLine":563,"endColumn":54,"suggestions":"2193"},{"ruleId":"1814","severity":1,"message":"1815","line":563,"column":64,"nodeType":"1816","messageId":"1817","endLine":563,"endColumn":67,"suggestions":"2194"},{"ruleId":"1814","severity":1,"message":"1815","line":563,"column":75,"nodeType":"1816","messageId":"1817","endLine":563,"endColumn":78,"suggestions":"2195"},{"ruleId":"1814","severity":1,"message":"1815","line":564,"column":19,"nodeType":"1816","messageId":"1817","endLine":564,"endColumn":22,"suggestions":"2196"},{"ruleId":"1814","severity":1,"message":"1815","line":580,"column":23,"nodeType":"1816","messageId":"1817","endLine":580,"endColumn":26,"suggestions":"2197"},{"ruleId":"1814","severity":1,"message":"1815","line":596,"column":52,"nodeType":"1816","messageId":"1817","endLine":596,"endColumn":55,"suggestions":"2198"},{"ruleId":"1814","severity":1,"message":"1815","line":608,"column":49,"nodeType":"1816","messageId":"1817","endLine":608,"endColumn":52,"suggestions":"2199"},{"ruleId":"1814","severity":1,"message":"1815","line":620,"column":56,"nodeType":"1816","messageId":"1817","endLine":620,"endColumn":59,"suggestions":"2200"},{"ruleId":"1814","severity":1,"message":"1815","line":620,"column":74,"nodeType":"1816","messageId":"1817","endLine":620,"endColumn":77,"suggestions":"2201"},{"ruleId":"1814","severity":1,"message":"1815","line":627,"column":40,"nodeType":"1816","messageId":"1817","endLine":627,"endColumn":43,"suggestions":"2202"},{"ruleId":"1814","severity":1,"message":"1815","line":642,"column":31,"nodeType":"1816","messageId":"1817","endLine":642,"endColumn":34,"suggestions":"2203"},{"ruleId":"1814","severity":1,"message":"1815","line":760,"column":66,"nodeType":"1816","messageId":"1817","endLine":760,"endColumn":69,"suggestions":"2204"},{"ruleId":"1814","severity":1,"message":"1815","line":760,"column":76,"nodeType":"1816","messageId":"1817","endLine":760,"endColumn":79,"suggestions":"2205"},{"ruleId":"1814","severity":1,"message":"1815","line":760,"column":89,"nodeType":"1816","messageId":"1817","endLine":760,"endColumn":92,"suggestions":"2206"},{"ruleId":"1814","severity":1,"message":"1815","line":772,"column":52,"nodeType":"1816","messageId":"1817","endLine":772,"endColumn":55,"suggestions":"2207"},{"ruleId":"1814","severity":1,"message":"1815","line":784,"column":55,"nodeType":"1816","messageId":"1817","endLine":784,"endColumn":58,"suggestions":"2208"},{"ruleId":"1814","severity":1,"message":"1815","line":796,"column":62,"nodeType":"1816","messageId":"1817","endLine":796,"endColumn":65,"suggestions":"2209"},{"ruleId":"1814","severity":1,"message":"1815","line":796,"column":80,"nodeType":"1816","messageId":"1817","endLine":796,"endColumn":83,"suggestions":"2210"},{"ruleId":"1814","severity":1,"message":"1815","line":803,"column":40,"nodeType":"1816","messageId":"1817","endLine":803,"endColumn":43,"suggestions":"2211"},{"ruleId":"1814","severity":1,"message":"1815","line":810,"column":20,"nodeType":"1816","messageId":"1817","endLine":810,"endColumn":23,"suggestions":"2212"},{"ruleId":"1814","severity":1,"message":"1815","line":810,"column":49,"nodeType":"1816","messageId":"1817","endLine":810,"endColumn":52,"suggestions":"2213"},{"ruleId":"1814","severity":1,"message":"1815","line":837,"column":44,"nodeType":"1816","messageId":"1817","endLine":837,"endColumn":47,"suggestions":"2214"},{"ruleId":"1814","severity":1,"message":"1815","line":870,"column":15,"nodeType":"1816","messageId":"1817","endLine":870,"endColumn":18,"suggestions":"2215"},{"ruleId":"1814","severity":1,"message":"1815","line":871,"column":23,"nodeType":"1816","messageId":"1817","endLine":871,"endColumn":26,"suggestions":"2216"},{"ruleId":"1814","severity":1,"message":"1815","line":872,"column":20,"nodeType":"1816","messageId":"1817","endLine":872,"endColumn":23,"suggestions":"2217"},{"ruleId":"1814","severity":1,"message":"1815","line":873,"column":23,"nodeType":"1816","messageId":"1817","endLine":873,"endColumn":26,"suggestions":"2218"},{"ruleId":"1814","severity":1,"message":"1815","line":874,"column":18,"nodeType":"1816","messageId":"1817","endLine":874,"endColumn":21,"suggestions":"2219"},{"ruleId":"1814","severity":1,"message":"1815","line":875,"column":15,"nodeType":"1816","messageId":"1817","endLine":875,"endColumn":18,"suggestions":"2220"},{"ruleId":"1814","severity":1,"message":"1815","line":876,"column":21,"nodeType":"1816","messageId":"1817","endLine":876,"endColumn":24,"suggestions":"2221"},{"ruleId":"1814","severity":1,"message":"1815","line":894,"column":61,"nodeType":"1816","messageId":"1817","endLine":894,"endColumn":64,"suggestions":"2222"},{"ruleId":"1814","severity":1,"message":"1815","line":917,"column":29,"nodeType":"1816","messageId":"1817","endLine":917,"endColumn":32,"suggestions":"2223"},{"ruleId":"1814","severity":1,"message":"1815","line":917,"column":40,"nodeType":"1816","messageId":"1817","endLine":917,"endColumn":43,"suggestions":"2224"},{"ruleId":"1814","severity":1,"message":"1815","line":956,"column":61,"nodeType":"1816","messageId":"1817","endLine":956,"endColumn":64,"suggestions":"2225"},{"ruleId":"1814","severity":1,"message":"1815","line":965,"column":27,"nodeType":"1816","messageId":"1817","endLine":965,"endColumn":30,"suggestions":"2226"},{"ruleId":"1814","severity":1,"message":"1815","line":965,"column":38,"nodeType":"1816","messageId":"1817","endLine":965,"endColumn":41,"suggestions":"2227"},{"ruleId":"1814","severity":1,"message":"1815","line":993,"column":30,"nodeType":"1816","messageId":"1817","endLine":993,"endColumn":33,"suggestions":"2228"},{"ruleId":"1814","severity":1,"message":"1815","line":997,"column":30,"nodeType":"1816","messageId":"1817","endLine":997,"endColumn":33,"suggestions":"2229"},{"ruleId":"1814","severity":1,"message":"1815","line":1039,"column":58,"nodeType":"1816","messageId":"1817","endLine":1039,"endColumn":61,"suggestions":"2230"},{"ruleId":"1814","severity":1,"message":"1815","line":1047,"column":27,"nodeType":"1816","messageId":"1817","endLine":1047,"endColumn":30,"suggestions":"2231"},{"ruleId":"1814","severity":1,"message":"1815","line":1047,"column":38,"nodeType":"1816","messageId":"1817","endLine":1047,"endColumn":41,"suggestions":"2232"},{"ruleId":"1814","severity":1,"message":"1815","line":1081,"column":56,"nodeType":"1816","messageId":"1817","endLine":1081,"endColumn":59,"suggestions":"2233"},{"ruleId":"1814","severity":1,"message":"1815","line":1111,"column":55,"nodeType":"1816","messageId":"1817","endLine":1111,"endColumn":58,"suggestions":"2234"},{"ruleId":"1814","severity":1,"message":"1815","line":1145,"column":65,"nodeType":"1816","messageId":"1817","endLine":1145,"endColumn":68,"suggestions":"2235"},{"ruleId":"1814","severity":1,"message":"1815","line":1153,"column":27,"nodeType":"1816","messageId":"1817","endLine":1153,"endColumn":30,"suggestions":"2236"},{"ruleId":"1814","severity":1,"message":"1815","line":1153,"column":38,"nodeType":"1816","messageId":"1817","endLine":1153,"endColumn":41,"suggestions":"2237"},{"ruleId":"1814","severity":1,"message":"1815","line":1230,"column":55,"nodeType":"1816","messageId":"1817","endLine":1230,"endColumn":58,"suggestions":"2238"},{"ruleId":"1814","severity":1,"message":"1815","line":1238,"column":27,"nodeType":"1816","messageId":"1817","endLine":1238,"endColumn":30,"suggestions":"2239"},{"ruleId":"1814","severity":1,"message":"1815","line":1238,"column":38,"nodeType":"1816","messageId":"1817","endLine":1238,"endColumn":41,"suggestions":"2240"},{"ruleId":"1814","severity":1,"message":"1815","line":1264,"column":50,"nodeType":"1816","messageId":"1817","endLine":1264,"endColumn":53,"suggestions":"2241"},{"ruleId":"1814","severity":1,"message":"1815","line":1294,"column":52,"nodeType":"1816","messageId":"1817","endLine":1294,"endColumn":55,"suggestions":"2242"},{"ruleId":"1814","severity":1,"message":"1815","line":1331,"column":59,"nodeType":"1816","messageId":"1817","endLine":1331,"endColumn":62,"suggestions":"2243"},{"ruleId":"1814","severity":1,"message":"1815","line":1339,"column":27,"nodeType":"1816","messageId":"1817","endLine":1339,"endColumn":30,"suggestions":"2244"},{"ruleId":"1814","severity":1,"message":"1815","line":1339,"column":38,"nodeType":"1816","messageId":"1817","endLine":1339,"endColumn":41,"suggestions":"2245"},{"ruleId":"1814","severity":1,"message":"1815","line":1362,"column":61,"nodeType":"1816","messageId":"1817","endLine":1362,"endColumn":64,"suggestions":"2246"},{"ruleId":"1814","severity":1,"message":"1815","line":1370,"column":27,"nodeType":"1816","messageId":"1817","endLine":1370,"endColumn":30,"suggestions":"2247"},{"ruleId":"1814","severity":1,"message":"1815","line":1370,"column":38,"nodeType":"1816","messageId":"1817","endLine":1370,"endColumn":41,"suggestions":"2248"},{"ruleId":"1814","severity":1,"message":"1815","line":1399,"column":62,"nodeType":"1816","messageId":"1817","endLine":1399,"endColumn":65,"suggestions":"2249"},{"ruleId":"1814","severity":1,"message":"1815","line":1431,"column":58,"nodeType":"1816","messageId":"1817","endLine":1431,"endColumn":61,"suggestions":"2250"},{"ruleId":"1814","severity":1,"message":"1815","line":1459,"column":71,"nodeType":"1816","messageId":"1817","endLine":1459,"endColumn":74,"suggestions":"2251"},{"ruleId":"1814","severity":1,"message":"1815","line":1467,"column":27,"nodeType":"1816","messageId":"1817","endLine":1467,"endColumn":30,"suggestions":"2252"},{"ruleId":"1814","severity":1,"message":"1815","line":1467,"column":38,"nodeType":"1816","messageId":"1817","endLine":1467,"endColumn":41,"suggestions":"2253"},{"ruleId":"1814","severity":1,"message":"1815","line":1487,"column":71,"nodeType":"1816","messageId":"1817","endLine":1487,"endColumn":74,"suggestions":"2254"},{"ruleId":"1814","severity":1,"message":"1815","line":1495,"column":27,"nodeType":"1816","messageId":"1817","endLine":1495,"endColumn":30,"suggestions":"2255"},{"ruleId":"1814","severity":1,"message":"1815","line":1495,"column":38,"nodeType":"1816","messageId":"1817","endLine":1495,"endColumn":41,"suggestions":"2256"},{"ruleId":"1814","severity":1,"message":"1815","line":1518,"column":60,"nodeType":"1816","messageId":"1817","endLine":1518,"endColumn":63,"suggestions":"2257"},{"ruleId":"1814","severity":1,"message":"1815","line":1541,"column":54,"nodeType":"1816","messageId":"1817","endLine":1541,"endColumn":57,"suggestions":"2258"},{"ruleId":"1814","severity":1,"message":"1815","line":1564,"column":57,"nodeType":"1816","messageId":"1817","endLine":1564,"endColumn":60,"suggestions":"2259"},{"ruleId":"1814","severity":1,"message":"1815","line":1586,"column":56,"nodeType":"1816","messageId":"1817","endLine":1586,"endColumn":59,"suggestions":"2260"},{"ruleId":"1814","severity":1,"message":"1815","line":1615,"column":76,"nodeType":"1816","messageId":"1817","endLine":1615,"endColumn":79,"suggestions":"2261"},{"ruleId":"1814","severity":1,"message":"1815","line":2168,"column":17,"nodeType":"1816","messageId":"1817","endLine":2168,"endColumn":20,"suggestions":"2262"},{"ruleId":"1814","severity":1,"message":"1815","line":2234,"column":60,"nodeType":"1816","messageId":"1817","endLine":2234,"endColumn":63,"suggestions":"2263"},{"ruleId":"1814","severity":1,"message":"1815","line":2253,"column":58,"nodeType":"1816","messageId":"1817","endLine":2253,"endColumn":61,"suggestions":"2264"},{"ruleId":"2265","severity":2,"message":"2266","line":42,"column":9,"nodeType":"1919","endLine":42,"endColumn":13,"suppressions":"2267"},{"ruleId":"2268","severity":2,"message":"2269","line":42,"column":9,"nodeType":"2270","endLine":42,"endColumn":15,"suppressions":"2271"},{"ruleId":"2272","severity":2,"message":"2273","line":60,"column":5,"nodeType":"1919","endLine":60,"endColumn":13,"suppressions":"2274"},{"ruleId":"2272","severity":2,"message":"2273","line":323,"column":5,"nodeType":"1919","endLine":323,"endColumn":13,"suppressions":"2275"},{"ruleId":"2272","severity":2,"message":"2273","line":364,"column":5,"nodeType":"1919","endLine":364,"endColumn":13,"suppressions":"2276"},{"ruleId":"2272","severity":2,"message":"2273","line":405,"column":5,"nodeType":"1919","endLine":405,"endColumn":13,"suppressions":"2277"},{"ruleId":"2272","severity":2,"message":"2273","line":458,"column":5,"nodeType":"1919","endLine":458,"endColumn":13,"suppressions":"2278"},{"ruleId":"2272","severity":2,"message":"2273","line":485,"column":5,"nodeType":"1919","endLine":485,"endColumn":13,"suppressions":"2279"},{"ruleId":"2272","severity":2,"message":"2273","line":756,"column":5,"nodeType":"2280","endLine":756,"endColumn":18,"suppressions":"2281"},{"ruleId":"2272","severity":2,"message":"2282","line":756,"column":5,"nodeType":"2280","endLine":756,"endColumn":18,"suppressions":"2283"},{"ruleId":"2272","severity":2,"message":"2273","line":831,"column":5,"nodeType":"2280","endLine":831,"endColumn":24,"suppressions":"2284"},{"ruleId":"2272","severity":2,"message":"2282","line":831,"column":5,"nodeType":"2280","endLine":831,"endColumn":24,"suppressions":"2285"},{"ruleId":"2272","severity":2,"message":"2273","line":872,"column":26,"nodeType":"2280","endLine":872,"endColumn":39,"suppressions":"2286"},{"ruleId":"2272","severity":2,"message":"2282","line":872,"column":26,"nodeType":"2280","endLine":872,"endColumn":39,"suppressions":"2287"},{"ruleId":"2272","severity":2,"message":"2273","line":873,"column":29,"nodeType":"1919","endLine":873,"endColumn":39,"suppressions":"2288"},{"ruleId":"2272","severity":2,"message":"2273","line":2164,"column":5,"nodeType":"2280","endLine":2164,"endColumn":18,"suppressions":"2289"},{"ruleId":"2272","severity":2,"message":"2282","line":2164,"column":5,"nodeType":"2280","endLine":2164,"endColumn":18,"suppressions":"2290"},{"ruleId":"1814","severity":1,"message":"1815","line":17,"column":15,"nodeType":"1816","messageId":"1817","endLine":17,"endColumn":18,"suggestions":"2291"},{"ruleId":"1814","severity":1,"message":"1815","line":58,"column":21,"nodeType":"1816","messageId":"1817","endLine":58,"endColumn":24,"suggestions":"2292"},{"ruleId":"1814","severity":1,"message":"1815","line":10,"column":90,"nodeType":"1816","messageId":"1817","endLine":10,"endColumn":93,"suggestions":"2293"},{"ruleId":"1814","severity":1,"message":"1815","line":53,"column":18,"nodeType":"1816","messageId":"1817","endLine":53,"endColumn":21,"suggestions":"2294"},{"ruleId":"1814","severity":1,"message":"1815","line":72,"column":12,"nodeType":"1816","messageId":"1817","endLine":72,"endColumn":15,"suggestions":"2295"},{"ruleId":"1814","severity":1,"message":"1815","line":90,"column":12,"nodeType":"1816","messageId":"1817","endLine":90,"endColumn":15,"suggestions":"2296"},{"ruleId":"1814","severity":1,"message":"1815","line":449,"column":29,"nodeType":"1816","messageId":"1817","endLine":449,"endColumn":32,"suggestions":"2297"},{"ruleId":"1814","severity":1,"message":"1815","line":18,"column":22,"nodeType":"1816","messageId":"1817","endLine":18,"endColumn":25,"suggestions":"2298"},{"ruleId":"1814","severity":1,"message":"1815","line":17,"column":29,"nodeType":"1816","messageId":"1817","endLine":17,"endColumn":32,"suggestions":"2299"},{"ruleId":"1814","severity":1,"message":"1815","line":19,"column":69,"nodeType":"1816","messageId":"1817","endLine":19,"endColumn":72,"suggestions":"2300"},{"ruleId":"1814","severity":1,"message":"1815","line":19,"column":78,"nodeType":"1816","messageId":"1817","endLine":19,"endColumn":81,"suggestions":"2301"},{"ruleId":"1814","severity":1,"message":"1815","line":20,"column":66,"nodeType":"1816","messageId":"1817","endLine":20,"endColumn":69,"suggestions":"2302"},{"ruleId":"1814","severity":1,"message":"1815","line":17,"column":22,"nodeType":"1816","messageId":"1817","endLine":17,"endColumn":25,"suggestions":"2303"},{"ruleId":"1814","severity":1,"message":"1815","line":18,"column":26,"nodeType":"1816","messageId":"1817","endLine":18,"endColumn":29,"suggestions":"2304"},{"ruleId":"1814","severity":1,"message":"1815","line":32,"column":16,"nodeType":"1816","messageId":"1817","endLine":32,"endColumn":19,"suggestions":"2305"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":8,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":11,"suggestions":"2306"},{"ruleId":"1814","severity":1,"message":"1815","line":16,"column":8,"nodeType":"1816","messageId":"1817","endLine":16,"endColumn":11,"suggestions":"2307"},{"ruleId":"1814","severity":1,"message":"1815","line":30,"column":71,"nodeType":"1816","messageId":"1817","endLine":30,"endColumn":74,"suggestions":"2308"},{"ruleId":"1814","severity":1,"message":"1815","line":21,"column":10,"nodeType":"1816","messageId":"1817","endLine":21,"endColumn":13,"suggestions":"2309"},{"ruleId":"1814","severity":1,"message":"1815","line":22,"column":16,"nodeType":"1816","messageId":"1817","endLine":22,"endColumn":19,"suggestions":"2310"},{"ruleId":"1814","severity":1,"message":"1815","line":24,"column":64,"nodeType":"1816","messageId":"1817","endLine":24,"endColumn":67,"suggestions":"2311"},{"ruleId":"1814","severity":1,"message":"1815","line":28,"column":29,"nodeType":"1816","messageId":"1817","endLine":28,"endColumn":32,"suggestions":"2312"},{"ruleId":"1814","severity":1,"message":"1815","line":28,"column":34,"nodeType":"1816","messageId":"1817","endLine":28,"endColumn":37,"suggestions":"2313"},{"ruleId":"1814","severity":1,"message":"1815","line":16,"column":8,"nodeType":"1816","messageId":"1817","endLine":16,"endColumn":11,"suggestions":"2314"},{"ruleId":"1814","severity":1,"message":"1815","line":17,"column":11,"nodeType":"1816","messageId":"1817","endLine":17,"endColumn":14,"suggestions":"2315"},{"ruleId":"1814","severity":1,"message":"1815","line":24,"column":27,"nodeType":"1816","messageId":"1817","endLine":24,"endColumn":30,"suggestions":"2316"},{"ruleId":"1814","severity":1,"message":"1815","line":28,"column":64,"nodeType":"1816","messageId":"1817","endLine":28,"endColumn":67,"suggestions":"2317"},{"ruleId":"1814","severity":1,"message":"1815","line":32,"column":29,"nodeType":"1816","messageId":"1817","endLine":32,"endColumn":32,"suggestions":"2318"},{"ruleId":"1814","severity":1,"message":"1815","line":32,"column":34,"nodeType":"1816","messageId":"1817","endLine":32,"endColumn":37,"suggestions":"2319"},{"ruleId":"1814","severity":1,"message":"1815","line":4,"column":11,"nodeType":"1816","messageId":"1817","endLine":4,"endColumn":14,"suggestions":"2320"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":12,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":15,"suggestions":"2321"},{"ruleId":"1814","severity":1,"message":"1815","line":3,"column":18,"nodeType":"1816","messageId":"1817","endLine":3,"endColumn":21,"suggestions":"2322"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":12,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":15,"suggestions":"2323"},{"ruleId":"1814","severity":1,"message":"1815","line":4,"column":12,"nodeType":"1816","messageId":"1817","endLine":4,"endColumn":15,"suggestions":"2324"},{"ruleId":"1814","severity":1,"message":"1815","line":8,"column":15,"nodeType":"1816","messageId":"1817","endLine":8,"endColumn":18,"suggestions":"2325"},{"ruleId":"1814","severity":1,"message":"1815","line":43,"column":58,"nodeType":"1816","messageId":"1817","endLine":43,"endColumn":61,"suggestions":"2326"},{"ruleId":"1814","severity":1,"message":"1815","line":43,"column":63,"nodeType":"1816","messageId":"1817","endLine":43,"endColumn":66,"suggestions":"2327"},{"ruleId":"1814","severity":1,"message":"1815","line":4,"column":15,"nodeType":"1816","messageId":"1817","endLine":4,"endColumn":18,"suggestions":"2328"},{"ruleId":"1814","severity":1,"message":"1815","line":4,"column":15,"nodeType":"1816","messageId":"1817","endLine":4,"endColumn":18,"suggestions":"2329"},{"ruleId":"1814","severity":1,"message":"1815","line":3,"column":9,"nodeType":"1816","messageId":"1817","endLine":3,"endColumn":12,"suggestions":"2330"},{"ruleId":"1814","severity":1,"message":"1815","line":4,"column":9,"nodeType":"1816","messageId":"1817","endLine":4,"endColumn":12,"suggestions":"2331"},{"ruleId":"1814","severity":1,"message":"1815","line":7,"column":10,"nodeType":"1816","messageId":"1817","endLine":7,"endColumn":13,"suggestions":"2332"},{"ruleId":"1814","severity":1,"message":"1815","line":10,"column":11,"nodeType":"1816","messageId":"1817","endLine":10,"endColumn":14,"suggestions":"2333"},{"ruleId":"1814","severity":1,"message":"1815","line":15,"column":12,"nodeType":"1816","messageId":"1817","endLine":15,"endColumn":15,"suggestions":"2334"},{"ruleId":"1814","severity":1,"message":"1815","line":7,"column":12,"nodeType":"1816","messageId":"1817","endLine":7,"endColumn":15,"suggestions":"2335","suppressions":"2336"},{"ruleId":"1814","severity":1,"message":"1815","line":4,"column":27,"nodeType":"1816","messageId":"1817","endLine":4,"endColumn":30,"suggestions":"2337"},{"ruleId":"1814","severity":1,"message":"1815","line":4,"column":56,"nodeType":"1816","messageId":"1817","endLine":4,"endColumn":59,"suggestions":"2338"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":10,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":13,"suggestions":"2339"},{"ruleId":"1814","severity":1,"message":"1815","line":16,"column":33,"nodeType":"1816","messageId":"1817","endLine":16,"endColumn":36,"suggestions":"2340"},{"ruleId":"1814","severity":1,"message":"1815","line":16,"column":49,"nodeType":"1816","messageId":"1817","endLine":16,"endColumn":52,"suggestions":"2341"},{"ruleId":"1814","severity":1,"message":"1815","line":30,"column":62,"nodeType":"1816","messageId":"1817","endLine":30,"endColumn":65,"suggestions":"2342"},{"ruleId":"1814","severity":1,"message":"1815","line":35,"column":30,"nodeType":"1816","messageId":"1817","endLine":35,"endColumn":33,"suggestions":"2343"},{"ruleId":"1814","severity":1,"message":"1815","line":42,"column":23,"nodeType":"1816","messageId":"1817","endLine":42,"endColumn":26,"suggestions":"2344"},{"ruleId":"1814","severity":1,"message":"1815","line":42,"column":52,"nodeType":"1816","messageId":"1817","endLine":42,"endColumn":55,"suggestions":"2345"},{"ruleId":"1814","severity":1,"message":"1815","line":84,"column":42,"nodeType":"1816","messageId":"1817","endLine":84,"endColumn":45,"suggestions":"2346"},{"ruleId":"1814","severity":1,"message":"1815","line":84,"column":53,"nodeType":"1816","messageId":"1817","endLine":84,"endColumn":56,"suggestions":"2347"},{"ruleId":"1814","severity":1,"message":"1815","line":88,"column":21,"nodeType":"1816","messageId":"1817","endLine":88,"endColumn":24,"suggestions":"2348"},{"ruleId":"1814","severity":1,"message":"1815","line":105,"column":11,"nodeType":"1816","messageId":"1817","endLine":105,"endColumn":14,"suggestions":"2349"},{"ruleId":"1814","severity":1,"message":"1815","line":106,"column":11,"nodeType":"1816","messageId":"1817","endLine":106,"endColumn":14,"suggestions":"2350"},{"ruleId":"1814","severity":1,"message":"1815","line":107,"column":10,"nodeType":"1816","messageId":"1817","endLine":107,"endColumn":13,"suggestions":"2351"},{"ruleId":"1814","severity":1,"message":"1815","line":109,"column":14,"nodeType":"1816","messageId":"1817","endLine":109,"endColumn":17,"suggestions":"2352"},{"ruleId":"1814","severity":1,"message":"1815","line":111,"column":6,"nodeType":"1816","messageId":"1817","endLine":111,"endColumn":9,"suggestions":"2353"},{"ruleId":"1814","severity":1,"message":"1815","line":164,"column":20,"nodeType":"1816","messageId":"1817","endLine":164,"endColumn":23,"suggestions":"2354"},{"ruleId":"1814","severity":1,"message":"1815","line":165,"column":11,"nodeType":"1816","messageId":"1817","endLine":165,"endColumn":14,"suggestions":"2355"},{"ruleId":"1814","severity":1,"message":"1815","line":166,"column":14,"nodeType":"1816","messageId":"1817","endLine":166,"endColumn":17,"suggestions":"2356"},{"ruleId":"1814","severity":1,"message":"1815","line":184,"column":46,"nodeType":"1816","messageId":"1817","endLine":184,"endColumn":49,"suggestions":"2357"},{"ruleId":"1814","severity":1,"message":"1815","line":186,"column":21,"nodeType":"1816","messageId":"1817","endLine":186,"endColumn":24,"suggestions":"2358"},{"ruleId":"1814","severity":1,"message":"1815","line":63,"column":30,"nodeType":"1816","messageId":"1817","endLine":63,"endColumn":33,"suggestions":"2359"},{"ruleId":"1814","severity":1,"message":"1815","line":124,"column":37,"nodeType":"1816","messageId":"1817","endLine":124,"endColumn":40,"suggestions":"2360"},{"ruleId":"1814","severity":1,"message":"1815","line":166,"column":37,"nodeType":"1816","messageId":"1817","endLine":166,"endColumn":40,"suggestions":"2361"},{"ruleId":"1814","severity":1,"message":"1815","line":234,"column":37,"nodeType":"1816","messageId":"1817","endLine":234,"endColumn":40,"suggestions":"2362"},{"ruleId":"1814","severity":1,"message":"1815","line":297,"column":37,"nodeType":"1816","messageId":"1817","endLine":297,"endColumn":40,"suggestions":"2363"},{"ruleId":"1814","severity":1,"message":"1815","line":499,"column":30,"nodeType":"1816","messageId":"1817","endLine":499,"endColumn":33,"suggestions":"2364"},{"ruleId":"1814","severity":1,"message":"1815","line":510,"column":30,"nodeType":"1816","messageId":"1817","endLine":510,"endColumn":33,"suggestions":"2365"},{"ruleId":"1814","severity":1,"message":"1815","line":523,"column":30,"nodeType":"1816","messageId":"1817","endLine":523,"endColumn":33,"suggestions":"2366"},{"ruleId":"1814","severity":1,"message":"1815","line":902,"column":37,"nodeType":"1816","messageId":"1817","endLine":902,"endColumn":40,"suggestions":"2367"},{"ruleId":"1814","severity":1,"message":"1815","line":964,"column":37,"nodeType":"1816","messageId":"1817","endLine":964,"endColumn":40,"suggestions":"2368"},{"ruleId":"1814","severity":1,"message":"1815","line":1067,"column":37,"nodeType":"1816","messageId":"1817","endLine":1067,"endColumn":40,"suggestions":"2369"},{"ruleId":"1814","severity":1,"message":"1815","line":1232,"column":39,"nodeType":"1816","messageId":"1817","endLine":1232,"endColumn":42,"suggestions":"2370"},{"ruleId":"1814","severity":1,"message":"1815","line":1299,"column":39,"nodeType":"1816","messageId":"1817","endLine":1299,"endColumn":42,"suggestions":"2371"},{"ruleId":"1814","severity":1,"message":"1815","line":1669,"column":37,"nodeType":"1816","messageId":"1817","endLine":1669,"endColumn":40,"suggestions":"2372"},{"ruleId":"1814","severity":1,"message":"1815","line":1731,"column":37,"nodeType":"1816","messageId":"1817","endLine":1731,"endColumn":40,"suggestions":"2373"},{"ruleId":"1814","severity":1,"message":"1815","line":1834,"column":37,"nodeType":"1816","messageId":"1817","endLine":1834,"endColumn":40,"suggestions":"2374"},{"ruleId":"1814","severity":1,"message":"1815","line":54,"column":30,"nodeType":"1816","messageId":"1817","endLine":54,"endColumn":33,"suggestions":"2375"},{"ruleId":"1814","severity":1,"message":"1815","line":68,"column":30,"nodeType":"1816","messageId":"1817","endLine":68,"endColumn":33,"suggestions":"2376"},{"ruleId":"1814","severity":1,"message":"1815","line":7,"column":48,"nodeType":"1816","messageId":"1817","endLine":7,"endColumn":51,"suggestions":"2377"},{"ruleId":"1814","severity":1,"message":"1815","line":11,"column":50,"nodeType":"1816","messageId":"1817","endLine":11,"endColumn":53,"suggestions":"2378"},{"ruleId":"1814","severity":1,"message":"1815","line":15,"column":50,"nodeType":"1816","messageId":"1817","endLine":15,"endColumn":53,"suggestions":"2379"},{"ruleId":"1814","severity":1,"message":"1815","line":71,"column":16,"nodeType":"1816","messageId":"1817","endLine":71,"endColumn":19,"suggestions":"2380"},{"ruleId":"1814","severity":1,"message":"1815","line":106,"column":60,"nodeType":"1816","messageId":"1817","endLine":106,"endColumn":63,"suggestions":"2381"},{"ruleId":"1814","severity":1,"message":"1815","line":53,"column":35,"nodeType":"1816","messageId":"1817","endLine":53,"endColumn":38,"suggestions":"2382"},{"ruleId":"1814","severity":1,"message":"1815","line":53,"column":48,"nodeType":"1816","messageId":"1817","endLine":53,"endColumn":51,"suggestions":"2383"},{"ruleId":"1814","severity":1,"message":"1815","line":53,"column":63,"nodeType":"1816","messageId":"1817","endLine":53,"endColumn":66,"suggestions":"2384"},{"ruleId":"1814","severity":1,"message":"1815","line":53,"column":69,"nodeType":"1816","messageId":"1817","endLine":53,"endColumn":72,"suggestions":"2385"},{"ruleId":"1814","severity":1,"message":"1815","line":91,"column":38,"nodeType":"1816","messageId":"1817","endLine":91,"endColumn":41,"suggestions":"2386"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":36,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":39,"suggestions":"2387"},{"ruleId":"1814","severity":1,"message":"1815","line":9,"column":17,"nodeType":"1816","messageId":"1817","endLine":9,"endColumn":20,"suggestions":"2388"},{"ruleId":"1814","severity":1,"message":"1815","line":26,"column":34,"nodeType":"1816","messageId":"1817","endLine":26,"endColumn":37,"suggestions":"2389"},{"ruleId":"1814","severity":1,"message":"1815","line":68,"column":44,"nodeType":"1816","messageId":"1817","endLine":68,"endColumn":47,"suggestions":"2390"},{"ruleId":"1814","severity":1,"message":"1815","line":72,"column":38,"nodeType":"1816","messageId":"1817","endLine":72,"endColumn":41,"suggestions":"2391"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":15,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":18,"suggestions":"2392"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":7,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":10,"suggestions":"2393"},{"ruleId":"1814","severity":1,"message":"1815","line":9,"column":12,"nodeType":"1816","messageId":"1817","endLine":9,"endColumn":15,"suggestions":"2394"},{"ruleId":"1814","severity":1,"message":"1815","line":65,"column":34,"nodeType":"1816","messageId":"1817","endLine":65,"endColumn":37,"suggestions":"2395"},{"ruleId":"1814","severity":1,"message":"1815","line":74,"column":30,"nodeType":"1816","messageId":"1817","endLine":74,"endColumn":33,"suggestions":"2396"},{"ruleId":"1814","severity":1,"message":"1815","line":102,"column":53,"nodeType":"1816","messageId":"1817","endLine":102,"endColumn":56,"suggestions":"2397"},{"ruleId":"1814","severity":1,"message":"1815","line":114,"column":44,"nodeType":"1816","messageId":"1817","endLine":114,"endColumn":47,"suggestions":"2398"},{"ruleId":"1814","severity":1,"message":"1815","line":36,"column":23,"nodeType":"1816","messageId":"1817","endLine":36,"endColumn":26,"suggestions":"2399"},{"ruleId":"1814","severity":1,"message":"1815","line":36,"column":67,"nodeType":"1816","messageId":"1817","endLine":36,"endColumn":70,"suggestions":"2400"},{"ruleId":"1814","severity":1,"message":"1815","line":36,"column":84,"nodeType":"1816","messageId":"1817","endLine":36,"endColumn":87,"suggestions":"2401"},{"ruleId":"1814","severity":1,"message":"1815","line":68,"column":34,"nodeType":"1816","messageId":"1817","endLine":68,"endColumn":37,"suggestions":"2402"},{"ruleId":"1814","severity":1,"message":"1815","line":77,"column":30,"nodeType":"1816","messageId":"1817","endLine":77,"endColumn":33,"suggestions":"2403"},{"ruleId":"1814","severity":1,"message":"1815","line":60,"column":20,"nodeType":"1816","messageId":"1817","endLine":60,"endColumn":23,"suggestions":"2404"},{"ruleId":"1814","severity":1,"message":"1815","line":63,"column":17,"nodeType":"1816","messageId":"1817","endLine":63,"endColumn":20,"suggestions":"2405"},{"ruleId":"1814","severity":1,"message":"1815","line":86,"column":75,"nodeType":"1816","messageId":"1817","endLine":86,"endColumn":78,"suggestions":"2406"},{"ruleId":"1814","severity":1,"message":"1815","line":215,"column":54,"nodeType":"1816","messageId":"1817","endLine":215,"endColumn":57,"suggestions":"2407"},{"ruleId":"1814","severity":1,"message":"1815","line":236,"column":46,"nodeType":"1816","messageId":"1817","endLine":236,"endColumn":49,"suggestions":"2408"},{"ruleId":"1814","severity":1,"message":"1815","line":258,"column":46,"nodeType":"1816","messageId":"1817","endLine":258,"endColumn":49,"suggestions":"2409"},{"ruleId":"1814","severity":1,"message":"1815","line":285,"column":80,"nodeType":"1816","messageId":"1817","endLine":285,"endColumn":83,"suggestions":"2410"},{"ruleId":"1814","severity":1,"message":"1815","line":285,"column":86,"nodeType":"1816","messageId":"1817","endLine":285,"endColumn":89,"suggestions":"2411"},{"ruleId":"1814","severity":1,"message":"1815","line":290,"column":42,"nodeType":"1816","messageId":"1817","endLine":290,"endColumn":45,"suggestions":"2412"},{"ruleId":"1814","severity":1,"message":"1815","line":308,"column":19,"nodeType":"1816","messageId":"1817","endLine":308,"endColumn":22,"suggestions":"2413"},{"ruleId":"1814","severity":1,"message":"1815","line":312,"column":51,"nodeType":"1816","messageId":"1817","endLine":312,"endColumn":54,"suggestions":"2414"},{"ruleId":"1814","severity":1,"message":"1815","line":326,"column":9,"nodeType":"1816","messageId":"1817","endLine":326,"endColumn":12,"suggestions":"2415"},{"ruleId":"1814","severity":1,"message":"1815","line":327,"column":8,"nodeType":"1816","messageId":"1817","endLine":327,"endColumn":11,"suggestions":"2416"},{"ruleId":"1814","severity":1,"message":"1815","line":338,"column":29,"nodeType":"1816","messageId":"1817","endLine":338,"endColumn":32,"suggestions":"2417"},{"ruleId":"1814","severity":1,"message":"1815","line":394,"column":61,"nodeType":"1816","messageId":"1817","endLine":394,"endColumn":64,"suggestions":"2418"},{"ruleId":"1814","severity":1,"message":"1815","line":419,"column":8,"nodeType":"1816","messageId":"1817","endLine":419,"endColumn":11,"suggestions":"2419"},{"ruleId":"1814","severity":1,"message":"1815","line":420,"column":15,"nodeType":"1816","messageId":"1817","endLine":420,"endColumn":18,"suggestions":"2420"},{"ruleId":"1814","severity":1,"message":"1815","line":425,"column":34,"nodeType":"1816","messageId":"1817","endLine":425,"endColumn":37,"suggestions":"2421"},{"ruleId":"1814","severity":1,"message":"1815","line":443,"column":66,"nodeType":"1816","messageId":"1817","endLine":443,"endColumn":69,"suggestions":"2422"},{"ruleId":"1814","severity":1,"message":"1815","line":447,"column":17,"nodeType":"1816","messageId":"1817","endLine":447,"endColumn":20,"suggestions":"2423"},{"ruleId":"1814","severity":1,"message":"1815","line":463,"column":64,"nodeType":"1816","messageId":"1817","endLine":463,"endColumn":67,"suggestions":"2424"},{"ruleId":"1814","severity":1,"message":"1815","line":511,"column":38,"nodeType":"1816","messageId":"1817","endLine":511,"endColumn":41,"suggestions":"2425"},{"ruleId":"1814","severity":1,"message":"1815","line":559,"column":38,"nodeType":"1816","messageId":"1817","endLine":559,"endColumn":41,"suggestions":"2426"},{"ruleId":"1814","severity":1,"message":"1815","line":560,"column":25,"nodeType":"1816","messageId":"1817","endLine":560,"endColumn":28,"suggestions":"2427"},{"ruleId":"1814","severity":1,"message":"1815","line":589,"column":34,"nodeType":"1816","messageId":"1817","endLine":589,"endColumn":37,"suggestions":"2428"},{"ruleId":"1814","severity":1,"message":"1815","line":603,"column":18,"nodeType":"1816","messageId":"1817","endLine":603,"endColumn":21,"suggestions":"2429"},{"ruleId":"1814","severity":1,"message":"1815","line":606,"column":17,"nodeType":"1816","messageId":"1817","endLine":606,"endColumn":20,"suggestions":"2430"},{"ruleId":"1814","severity":1,"message":"1815","line":623,"column":42,"nodeType":"1816","messageId":"1817","endLine":623,"endColumn":45,"suggestions":"2431"},{"ruleId":"1814","severity":1,"message":"1815","line":716,"column":42,"nodeType":"1816","messageId":"1817","endLine":716,"endColumn":45,"suggestions":"2432"},{"ruleId":"1814","severity":1,"message":"1815","line":716,"column":53,"nodeType":"1816","messageId":"1817","endLine":716,"endColumn":56,"suggestions":"2433"},{"ruleId":"1814","severity":1,"message":"1815","line":752,"column":40,"nodeType":"1816","messageId":"1817","endLine":752,"endColumn":43,"suggestions":"2434"},{"ruleId":"1814","severity":1,"message":"1815","line":752,"column":54,"nodeType":"1816","messageId":"1817","endLine":752,"endColumn":57,"suggestions":"2435"},{"ruleId":"1814","severity":1,"message":"1815","line":753,"column":17,"nodeType":"1816","messageId":"1817","endLine":753,"endColumn":20,"suggestions":"2436"},{"ruleId":"1814","severity":1,"message":"1815","line":754,"column":37,"nodeType":"1816","messageId":"1817","endLine":754,"endColumn":40,"suggestions":"2437"},{"ruleId":"1814","severity":1,"message":"1815","line":761,"column":82,"nodeType":"1816","messageId":"1817","endLine":761,"endColumn":85,"suggestions":"2438"},{"ruleId":"1814","severity":1,"message":"1815","line":767,"column":81,"nodeType":"1816","messageId":"1817","endLine":767,"endColumn":84,"suggestions":"2439"},{"ruleId":"1814","severity":1,"message":"1815","line":767,"column":92,"nodeType":"1816","messageId":"1817","endLine":767,"endColumn":95,"suggestions":"2440"},{"ruleId":"1814","severity":1,"message":"1815","line":780,"column":79,"nodeType":"1816","messageId":"1817","endLine":780,"endColumn":82,"suggestions":"2441"},{"ruleId":"1814","severity":1,"message":"1815","line":780,"column":90,"nodeType":"1816","messageId":"1817","endLine":780,"endColumn":93,"suggestions":"2442"},{"ruleId":"1814","severity":1,"message":"1815","line":790,"column":79,"nodeType":"1816","messageId":"1817","endLine":790,"endColumn":82,"suggestions":"2443"},{"ruleId":"1814","severity":1,"message":"1815","line":790,"column":90,"nodeType":"1816","messageId":"1817","endLine":790,"endColumn":93,"suggestions":"2444"},{"ruleId":"1814","severity":1,"message":"1815","line":832,"column":43,"nodeType":"1816","messageId":"1817","endLine":832,"endColumn":46,"suggestions":"2445"},{"ruleId":"1814","severity":1,"message":"1815","line":832,"column":53,"nodeType":"1816","messageId":"1817","endLine":832,"endColumn":56,"suggestions":"2446"},{"ruleId":"1814","severity":1,"message":"1815","line":832,"column":64,"nodeType":"1816","messageId":"1817","endLine":832,"endColumn":67,"suggestions":"2447"},{"ruleId":"1814","severity":1,"message":"1815","line":832,"column":73,"nodeType":"1816","messageId":"1817","endLine":832,"endColumn":76,"suggestions":"2448"},{"ruleId":"1814","severity":1,"message":"1815","line":840,"column":43,"nodeType":"1816","messageId":"1817","endLine":840,"endColumn":46,"suggestions":"2449"},{"ruleId":"1814","severity":1,"message":"1815","line":840,"column":55,"nodeType":"1816","messageId":"1817","endLine":840,"endColumn":58,"suggestions":"2450"},{"ruleId":"1814","severity":1,"message":"1815","line":848,"column":51,"nodeType":"1816","messageId":"1817","endLine":848,"endColumn":54,"suggestions":"2451"},{"ruleId":"1814","severity":1,"message":"1815","line":848,"column":63,"nodeType":"1816","messageId":"1817","endLine":848,"endColumn":66,"suggestions":"2452"},{"ruleId":"1814","severity":1,"message":"1815","line":858,"column":45,"nodeType":"1816","messageId":"1817","endLine":858,"endColumn":48,"suggestions":"2453"},{"ruleId":"1814","severity":1,"message":"1815","line":858,"column":57,"nodeType":"1816","messageId":"1817","endLine":858,"endColumn":60,"suggestions":"2454"},{"ruleId":"1814","severity":1,"message":"1815","line":861,"column":39,"nodeType":"1816","messageId":"1817","endLine":861,"endColumn":42,"suggestions":"2455"},{"ruleId":"1814","severity":1,"message":"1815","line":861,"column":51,"nodeType":"1816","messageId":"1817","endLine":861,"endColumn":54,"suggestions":"2456"},{"ruleId":"1814","severity":1,"message":"1815","line":882,"column":41,"nodeType":"1816","messageId":"1817","endLine":882,"endColumn":44,"suggestions":"2457"},{"ruleId":"1814","severity":1,"message":"1815","line":884,"column":41,"nodeType":"1816","messageId":"1817","endLine":884,"endColumn":44,"suggestions":"2458"},{"ruleId":"1814","severity":1,"message":"1815","line":886,"column":41,"nodeType":"1816","messageId":"1817","endLine":886,"endColumn":44,"suggestions":"2459"},{"ruleId":"1814","severity":1,"message":"1815","line":888,"column":40,"nodeType":"1816","messageId":"1817","endLine":888,"endColumn":43,"suggestions":"2460"},{"ruleId":"1814","severity":1,"message":"1815","line":890,"column":42,"nodeType":"1816","messageId":"1817","endLine":890,"endColumn":45,"suggestions":"2461"},{"ruleId":"1814","severity":1,"message":"1815","line":892,"column":40,"nodeType":"1816","messageId":"1817","endLine":892,"endColumn":43,"suggestions":"2462"},{"ruleId":"1814","severity":1,"message":"1815","line":894,"column":41,"nodeType":"1816","messageId":"1817","endLine":894,"endColumn":44,"suggestions":"2463"},{"ruleId":"1814","severity":1,"message":"1815","line":896,"column":44,"nodeType":"1816","messageId":"1817","endLine":896,"endColumn":47,"suggestions":"2464"},{"ruleId":"1814","severity":1,"message":"1815","line":898,"column":41,"nodeType":"1816","messageId":"1817","endLine":898,"endColumn":44,"suggestions":"2465"},{"ruleId":"1814","severity":1,"message":"1815","line":900,"column":42,"nodeType":"1816","messageId":"1817","endLine":900,"endColumn":45,"suggestions":"2466"},{"ruleId":"1814","severity":1,"message":"1815","line":934,"column":29,"nodeType":"1816","messageId":"1817","endLine":934,"endColumn":32,"suggestions":"2467"},{"ruleId":"1814","severity":1,"message":"1815","line":941,"column":52,"nodeType":"1816","messageId":"1817","endLine":941,"endColumn":55,"suggestions":"2468"},{"ruleId":"1814","severity":1,"message":"1815","line":951,"column":9,"nodeType":"1816","messageId":"1817","endLine":951,"endColumn":12,"suggestions":"2469"},{"ruleId":"1814","severity":1,"message":"1815","line":953,"column":15,"nodeType":"1816","messageId":"1817","endLine":953,"endColumn":18,"suggestions":"2470"},{"ruleId":"1814","severity":1,"message":"1815","line":51,"column":15,"nodeType":"1816","messageId":"1817","endLine":51,"endColumn":18,"suggestions":"2471"},{"ruleId":"1814","severity":1,"message":"1815","line":59,"column":15,"nodeType":"1816","messageId":"1817","endLine":59,"endColumn":18,"suggestions":"2472"},{"ruleId":"1814","severity":1,"message":"1815","line":31,"column":62,"nodeType":"1816","messageId":"1817","endLine":31,"endColumn":65,"suggestions":"2473"},{"ruleId":"1814","severity":1,"message":"1815","line":84,"column":88,"nodeType":"1816","messageId":"1817","endLine":84,"endColumn":91,"suggestions":"2474"},{"ruleId":"1814","severity":1,"message":"1815","line":109,"column":18,"nodeType":"1816","messageId":"1817","endLine":109,"endColumn":21,"suggestions":"2475"},{"ruleId":"1814","severity":1,"message":"1815","line":112,"column":84,"nodeType":"1816","messageId":"1817","endLine":112,"endColumn":87,"suggestions":"2476"},{"ruleId":"1814","severity":1,"message":"1815","line":135,"column":75,"nodeType":"1816","messageId":"1817","endLine":135,"endColumn":78,"suggestions":"2477"},{"ruleId":"1814","severity":1,"message":"1815","line":158,"column":19,"nodeType":"1816","messageId":"1817","endLine":158,"endColumn":22,"suggestions":"2478"},{"ruleId":"1814","severity":1,"message":"1815","line":9,"column":36,"nodeType":"1816","messageId":"1817","endLine":9,"endColumn":39,"suggestions":"2479"},{"ruleId":"1814","severity":1,"message":"1815","line":9,"column":59,"nodeType":"1816","messageId":"1817","endLine":9,"endColumn":62,"suggestions":"2480"},{"ruleId":"1814","severity":1,"message":"1815","line":13,"column":20,"nodeType":"1816","messageId":"1817","endLine":13,"endColumn":23,"suggestions":"2481"},{"ruleId":"1814","severity":1,"message":"1815","line":46,"column":39,"nodeType":"1816","messageId":"1817","endLine":46,"endColumn":42,"suggestions":"2482"},{"ruleId":"1814","severity":1,"message":"1815","line":46,"column":55,"nodeType":"1816","messageId":"1817","endLine":46,"endColumn":58,"suggestions":"2483"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":36,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":39,"suggestions":"2484"},{"ruleId":"1814","severity":1,"message":"1815","line":6,"column":52,"nodeType":"1816","messageId":"1817","endLine":6,"endColumn":55,"suggestions":"2485"},{"ruleId":"1814","severity":1,"message":"1815","line":13,"column":21,"nodeType":"1816","messageId":"1817","endLine":13,"endColumn":24,"suggestions":"2486"},{"ruleId":"1814","severity":1,"message":"1815","line":2,"column":16,"nodeType":"1816","messageId":"1817","endLine":2,"endColumn":19,"suggestions":"2487"},{"ruleId":"1814","severity":1,"message":"1815","line":20,"column":51,"nodeType":"1816","messageId":"1817","endLine":20,"endColumn":54,"suggestions":"2488"},{"ruleId":"1814","severity":1,"message":"1815","line":27,"column":26,"nodeType":"1816","messageId":"1817","endLine":27,"endColumn":29,"suggestions":"2489"},{"ruleId":"1814","severity":1,"message":"1815","line":37,"column":51,"nodeType":"1816","messageId":"1817","endLine":37,"endColumn":54,"suggestions":"2490"},{"ruleId":"1814","severity":1,"message":"1815","line":4,"column":34,"nodeType":"1816","messageId":"1817","endLine":4,"endColumn":37,"suggestions":"2491"},{"ruleId":"1814","severity":1,"message":"1815","line":4,"column":44,"nodeType":"1816","messageId":"1817","endLine":4,"endColumn":47,"suggestions":"2492"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":30,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":33,"suggestions":"2493"},{"ruleId":"1814","severity":1,"message":"1815","line":5,"column":40,"nodeType":"1816","messageId":"1817","endLine":5,"endColumn":43,"suggestions":"2494"},{"ruleId":"1814","severity":1,"message":"1815","line":17,"column":33,"nodeType":"1816","messageId":"1817","endLine":17,"endColumn":36,"suggestions":"2495"},{"ruleId":"1814","severity":1,"message":"1815","line":17,"column":43,"nodeType":"1816","messageId":"1817","endLine":17,"endColumn":46,"suggestions":"2496"},{"ruleId":"1814","severity":1,"message":"1815","line":18,"column":32,"nodeType":"1816","messageId":"1817","endLine":18,"endColumn":35,"suggestions":"2497"},{"ruleId":"1814","severity":1,"message":"1815","line":19,"column":18,"nodeType":"1816","messageId":"1817","endLine":19,"endColumn":21,"suggestions":"2498"},{"ruleId":"1814","severity":1,"message":"1815","line":20,"column":37,"nodeType":"1816","messageId":"1817","endLine":20,"endColumn":40,"suggestions":"2499"},{"ruleId":"1814","severity":1,"message":"1815","line":20,"column":47,"nodeType":"1816","messageId":"1817","endLine":20,"endColumn":50,"suggestions":"2500"},{"ruleId":"1814","severity":1,"message":"1815","line":34,"column":37,"nodeType":"1816","messageId":"1817","endLine":34,"endColumn":40,"suggestions":"2501"},{"ruleId":"1814","severity":1,"message":"1815","line":37,"column":31,"nodeType":"1816","messageId":"1817","endLine":37,"endColumn":34,"suggestions":"2502"},{"ruleId":"1814","severity":1,"message":"1815","line":42,"column":30,"nodeType":"1816","messageId":"1817","endLine":42,"endColumn":33,"suggestions":"2503"},{"ruleId":"1814","severity":1,"message":"1815","line":42,"column":47,"nodeType":"1816","messageId":"1817","endLine":42,"endColumn":50,"suggestions":"2504"},{"ruleId":"1814","severity":1,"message":"1815","line":49,"column":15,"nodeType":"1816","messageId":"1817","endLine":49,"endColumn":18,"suggestions":"2505"},{"ruleId":"1814","severity":1,"message":"1815","line":50,"column":13,"nodeType":"1816","messageId":"1817","endLine":50,"endColumn":16,"suggestions":"2506"},{"ruleId":"1814","severity":1,"message":"1815","line":51,"column":13,"nodeType":"1816","messageId":"1817","endLine":51,"endColumn":16,"suggestions":"2507"},{"ruleId":"1814","severity":1,"message":"1815","line":52,"column":13,"nodeType":"1816","messageId":"1817","endLine":52,"endColumn":16,"suggestions":"2508"},{"ruleId":"1814","severity":1,"message":"1815","line":53,"column":14,"nodeType":"1816","messageId":"1817","endLine":53,"endColumn":17,"suggestions":"2509"},{"ruleId":"1814","severity":1,"message":"1815","line":79,"column":22,"nodeType":"1816","messageId":"1817","endLine":79,"endColumn":25,"suggestions":"2510"},{"ruleId":"1814","severity":1,"message":"1815","line":96,"column":40,"nodeType":"1816","messageId":"1817","endLine":96,"endColumn":43,"suggestions":"2511"},{"ruleId":"1814","severity":1,"message":"1815","line":96,"column":51,"nodeType":"1816","messageId":"1817","endLine":96,"endColumn":54,"suggestions":"2512"},{"ruleId":"1814","severity":1,"message":"1815","line":96,"column":65,"nodeType":"1816","messageId":"1817","endLine":96,"endColumn":68,"suggestions":"2513"},{"ruleId":"1814","severity":1,"message":"1815","line":96,"column":80,"nodeType":"1816","messageId":"1817","endLine":96,"endColumn":83,"suggestions":"2514"},{"ruleId":"1814","severity":1,"message":"1815","line":104,"column":44,"nodeType":"1816","messageId":"1817","endLine":104,"endColumn":47,"suggestions":"2515"},{"ruleId":"1814","severity":1,"message":"1815","line":104,"column":56,"nodeType":"1816","messageId":"1817","endLine":104,"endColumn":59,"suggestions":"2516"},{"ruleId":"1814","severity":1,"message":"1815","line":104,"column":69,"nodeType":"1816","messageId":"1817","endLine":104,"endColumn":72,"suggestions":"2517"},{"ruleId":"1814","severity":1,"message":"1815","line":104,"column":91,"nodeType":"1816","messageId":"1817","endLine":104,"endColumn":94,"suggestions":"2518"},{"ruleId":"1814","severity":1,"message":"1815","line":134,"column":26,"nodeType":"1816","messageId":"1817","endLine":134,"endColumn":29,"suggestions":"2519"},{"ruleId":"1814","severity":1,"message":"1815","line":134,"column":37,"nodeType":"1816","messageId":"1817","endLine":134,"endColumn":40,"suggestions":"2520"},{"ruleId":"1814","severity":1,"message":"1815","line":136,"column":52,"nodeType":"1816","messageId":"1817","endLine":136,"endColumn":55,"suggestions":"2521"},{"ruleId":"2522","severity":2,"message":"2523","line":66,"column":44,"nodeType":"2524","messageId":"2525","endLine":66,"endColumn":45,"suggestions":"2526","suppressions":"2527"},{"ruleId":"2522","severity":2,"message":"2528","line":108,"column":36,"nodeType":"2524","messageId":"2525","endLine":108,"endColumn":37,"suggestions":"2529","suppressions":"2530"},{"ruleId":"1814","severity":1,"message":"1815","line":22,"column":34,"nodeType":"1816","messageId":"1817","endLine":22,"endColumn":37,"suggestions":"2531"},{"ruleId":"1814","severity":1,"message":"1815","line":49,"column":10,"nodeType":"1816","messageId":"1817","endLine":49,"endColumn":13,"suggestions":"2532"},"@typescript-eslint/no-explicit-any","Unexpected any. Specify a different type.","TSAnyKeyword","unexpectedAny",["2533","2534"],["2535","2536"],["2537","2538"],["2539","2540"],["2541","2542"],["2543","2544"],["2545","2546"],["2547","2548"],["2549","2550"],["2551","2552"],["2553","2554"],["2555","2556"],["2557","2558"],["2559","2560"],["2561","2562"],["2563","2564"],["2565","2566"],["2567","2568"],["2569","2570"],["2571","2572"],["2573","2574"],["2575","2576"],["2577","2578"],["2579","2580"],["2581","2582"],["2583","2584"],["2585","2586"],["2587","2588"],["2589","2590"],["2591","2592"],["2593","2594"],["2595","2596"],["2597","2598"],["2599","2600"],["2601","2602"],["2603","2604"],["2605","2606"],["2607","2608"],["2609","2610"],["2611","2612"],["2613","2614"],["2615","2616"],["2617","2618"],["2619","2620"],["2621","2622"],["2623","2624"],["2625","2626"],["2627","2628"],["2629","2630"],["2631","2632"],["2633","2634"],["2635","2636"],["2637","2638"],["2639","2640"],["2641","2642"],["2643","2644"],["2645","2646"],["2647","2648"],["2649","2650"],["2651","2652"],["2653","2654"],["2655","2656"],["2657","2658"],["2659","2660"],["2661","2662"],["2663","2664"],["2665","2666"],["2667","2668"],["2669","2670"],["2671","2672"],["2673","2674"],["2675","2676"],["2677","2678"],["2679","2680"],["2681","2682"],["2683","2684"],["2685","2686"],["2687","2688"],["2689","2690"],["2691","2692"],["2693","2694"],["2695","2696"],["2697","2698"],["2699","2700"],["2701","2702"],["2703","2704"],["2705","2706"],["2707","2708"],["2709","2710"],["2711","2712"],["2713","2714"],["2715","2716"],["2717","2718"],["2719","2720"],["2721","2722"],["2723","2724"],["2725","2726"],["2727","2728"],["2729","2730"],"mocha/no-skipped-tests","Unexpected skipped mocha test.","Identifier",["2731","2732"],["2733","2734"],["2735","2736"],["2737","2738"],["2739","2740"],["2741","2742"],["2743","2744"],["2745","2746"],["2747","2748"],["2749","2750"],["2751","2752"],["2753","2754"],["2755","2756"],["2757","2758"],["2759","2760"],["2761","2762"],["2763","2764"],["2765","2766"],["2767","2768"],["2769","2770"],["2771","2772"],["2773","2774"],["2775","2776"],["2777","2778"],["2779","2780"],["2781","2782"],["2783","2784"],["2785","2786"],["2787","2788"],["2789","2790"],["2791","2792"],["2793","2794"],["2795","2796"],["2797","2798"],["2799","2800"],["2801","2802"],["2803","2804"],["2805","2806"],["2807","2808"],["2809","2810"],["2811","2812"],["2813","2814"],["2815","2816"],["2817","2818"],["2819","2820"],["2821","2822"],["2823","2824"],["2825","2826"],["2827","2828"],["2829","2830"],["2831","2832"],["2833","2834"],["2835","2836"],["2837","2838"],["2839","2840"],["2841","2842"],["2843","2844"],["2845","2846"],["2847","2848"],["2849","2850"],["2851","2852"],["2853","2854"],["2855","2856"],["2857","2858"],["2859","2860"],["2861","2862"],["2863","2864"],["2865","2866"],["2867","2868"],["2869","2870"],["2871","2872"],["2873","2874"],["2875","2876"],["2877","2878"],["2879","2880"],["2881","2882"],["2883","2884"],["2885","2886"],["2887","2888"],["2889","2890"],["2891","2892"],["2893","2894"],["2895","2896"],["2897","2898"],["2899","2900"],["2901","2902"],["2903","2904"],["2905","2906"],["2907","2908"],["2909","2910"],["2911","2912"],["2913","2914"],["2915","2916"],["2917","2918"],["2919","2920"],["2921","2922"],["2923","2924"],["2925","2926"],["2927","2928"],["2929","2930"],["2931","2932"],["2933","2934"],["2935","2936"],["2937","2938"],["2939","2940"],["2941","2942"],["2943","2944"],["2945","2946"],["2947","2948"],["2949","2950"],["2951","2952"],["2953","2954"],["2955","2956"],["2957","2958"],["2959","2960"],["2961","2962"],["2963","2964"],["2965","2966"],["2967","2968"],["2969","2970"],["2971","2972"],["2973","2974"],["2975","2976"],["2977","2978"],["2979","2980"],["2981","2982"],["2983","2984"],["2985","2986"],["2987","2988"],["2989","2990"],["2991","2992"],["2993","2994"],["2995","2996"],["2997","2998"],["2999","3000"],["3001","3002"],["3003","3004"],["3005","3006"],["3007","3008"],["3009","3010"],["3011","3012"],["3013","3014"],["3015","3016"],["3017","3018"],["3019","3020"],["3021","3022"],["3023","3024"],["3025","3026"],["3027","3028"],["3029","3030"],["3031","3032"],["3033","3034"],["3035","3036"],["3037","3038"],["3039","3040"],["3041","3042"],["3043","3044"],["3045","3046"],["3047","3048"],["3049","3050"],["3051","3052"],["3053","3054"],["3055","3056"],["3057","3058"],["3059","3060"],["3061","3062"],["3063","3064"],["3065","3066"],["3067","3068"],["3069","3070"],["3071","3072"],["3073","3074"],["3075","3076"],["3077","3078"],["3079","3080"],["3081","3082"],["3083","3084"],["3085","3086"],["3087","3088"],["3089","3090"],["3091","3092"],["3093","3094"],["3095","3096"],["3097","3098"],["3099","3100"],["3101","3102"],["3103","3104"],["3105","3106"],["3107","3108"],["3109","3110"],["3111","3112"],["3113","3114"],["3115","3116"],["3117","3118"],["3119","3120"],["3121","3122"],["3123","3124"],["3125","3126"],["3127","3128"],["3129","3130"],["3131","3132"],["3133","3134"],["3135","3136"],["3137","3138"],["3139","3140"],["3141","3142"],["3143","3144"],["3145","3146"],["3147","3148"],["3149","3150"],["3151","3152"],["3153","3154"],["3155","3156"],["3157","3158"],["3159","3160"],["3161","3162"],["3163","3164"],["3165","3166"],["3167","3168"],["3169","3170"],["3171","3172"],["3173","3174"],["3175","3176"],["3177","3178"],["3179","3180"],["3181","3182"],["3183","3184"],["3185","3186"],["3187","3188"],["3189","3190"],["3191","3192"],["3193","3194"],["3195","3196"],["3197","3198"],["3199","3200"],["3201","3202"],["3203","3204"],["3205","3206"],["3207","3208"],["3209","3210"],["3211","3212"],["3213","3214"],["3215","3216"],["3217","3218"],["3219","3220"],["3221","3222"],["3223","3224"],["3225","3226"],["3227","3228"],["3229","3230"],["3231","3232"],["3233","3234"],["3235","3236"],["3237","3238"],["3239","3240"],["3241","3242"],["3243","3244"],["3245","3246"],["3247","3248"],["3249","3250"],["3251","3252"],["3253","3254"],"mocha/no-top-level-hooks","Unexpected use of Mocha `beforeEach` hook outside of a test suite",["3255","3256"],["3257","3258"],["3259","3260"],["3261","3262"],["3263","3264"],["3265","3266"],["3267","3268"],["3269","3270"],["3271","3272"],["3273","3274"],["3275","3276"],["3277","3278"],["3279","3280"],["3281","3282"],["3283","3284"],["3285","3286"],["3287","3288"],["3289","3290"],["3291","3292"],["3293","3294"],["3295","3296"],["3297","3298"],["3299","3300"],["3301","3302"],["3303","3304"],["3305","3306"],["3307","3308"],["3309","3310"],["3311","3312"],["3313","3314"],["3315","3316"],["3317","3318"],["3319","3320"],["3321","3322"],["3323","3324"],["3325","3326"],["3327","3328"],["3329","3330"],["3331","3332"],["3333","3334"],["3335","3336"],["3337","3338"],["3339","3340"],["3341","3342"],["3343","3344"],["3345","3346"],["3347","3348"],["3349","3350"],["3351","3352"],["3353","3354"],["3355","3356"],["3357","3358"],["3359","3360"],["3361","3362"],["3363","3364"],["3365","3366"],["3367","3368"],["3369","3370"],["3371","3372"],["3373","3374"],["3375","3376"],["3377","3378"],["3379","3380"],["3381","3382"],["3383","3384"],["3385","3386"],["3387","3388"],["3389","3390"],["3391","3392"],["3393","3394"],["3395","3396"],["3397","3398"],["3399","3400"],["3401","3402"],["3403","3404"],["3405","3406"],["3407","3408"],["3409","3410"],["3411","3412"],["3413","3414"],["3415","3416"],"mocha/no-nested-tests","Unexpected test nested within another test.",["3417"],"mocha/no-empty-description","Unexpected empty test description.","CallExpression",["3418"],"mocha/no-setup-in-describe","Unexpected function call in describe block.",["3419"],["3420"],["3421"],["3422"],["3423"],["3424"],"MemberExpression",["3425"],"Unexpected member expression in describe block. Member expressions may call functions via getters.",["3426"],["3427"],["3428"],["3429"],["3430"],["3431"],["3432"],["3433"],["3434","3435"],["3436","3437"],["3438","3439"],["3440","3441"],["3442","3443"],["3444","3445"],["3446","3447"],["3448","3449"],["3450","3451"],["3452","3453"],["3454","3455"],["3456","3457"],["3458","3459"],["3460","3461"],["3462","3463"],["3464","3465"],["3466","3467"],["3468","3469"],["3470","3471"],["3472","3473"],["3474","3475"],["3476","3477"],["3478","3479"],["3480","3481"],["3482","3483"],["3484","3485"],["3486","3487"],["3488","3489"],["3490","3491"],["3492","3493"],["3494","3495"],["3496","3497"],["3498","3499"],["3500","3501"],["3502","3503"],["3504","3505"],["3506","3507"],["3508","3509"],["3510","3511"],["3512","3513"],["3514","3515"],["3516","3517"],["3518","3519"],["3520","3521"],["3522","3523"],["3524"],["3525","3526"],["3527","3528"],["3529","3530"],["3531","3532"],["3533","3534"],["3535","3536"],["3537","3538"],["3539","3540"],["3541","3542"],["3543","3544"],["3545","3546"],["3547","3548"],["3549","3550"],["3551","3552"],["3553","3554"],["3555","3556"],["3557","3558"],["3559","3560"],["3561","3562"],["3563","3564"],["3565","3566"],["3567","3568"],["3569","3570"],["3571","3572"],["3573","3574"],["3575","3576"],["3577","3578"],["3579","3580"],["3581","3582"],["3583","3584"],["3585","3586"],["3587","3588"],["3589","3590"],["3591","3592"],["3593","3594"],["3595","3596"],["3597","3598"],["3599","3600"],["3601","3602"],["3603","3604"],["3605","3606"],["3607","3608"],["3609","3610"],["3611","3612"],["3613","3614"],["3615","3616"],["3617","3618"],["3619","3620"],["3621","3622"],["3623","3624"],["3625","3626"],["3627","3628"],["3629","3630"],["3631","3632"],["3633","3634"],["3635","3636"],["3637","3638"],["3639","3640"],["3641","3642"],["3643","3644"],["3645","3646"],["3647","3648"],["3649","3650"],["3651","3652"],["3653","3654"],["3655","3656"],["3657","3658"],["3659","3660"],["3661","3662"],["3663","3664"],["3665","3666"],["3667","3668"],["3669","3670"],["3671","3672"],["3673","3674"],["3675","3676"],["3677","3678"],["3679","3680"],["3681","3682"],["3683","3684"],["3685","3686"],["3687","3688"],["3689","3690"],["3691","3692"],["3693","3694"],["3695","3696"],["3697","3698"],["3699","3700"],["3701","3702"],["3703","3704"],["3705","3706"],["3707","3708"],["3709","3710"],["3711","3712"],["3713","3714"],["3715","3716"],["3717","3718"],["3719","3720"],["3721","3722"],["3723","3724"],["3725","3726"],["3727","3728"],["3729","3730"],["3731","3732"],["3733","3734"],["3735","3736"],["3737","3738"],["3739","3740"],["3741","3742"],["3743","3744"],["3745","3746"],["3747","3748"],["3749","3750"],["3751","3752"],["3753","3754"],["3755","3756"],["3757","3758"],["3759","3760"],["3761","3762"],["3763","3764"],["3765","3766"],["3767","3768"],["3769","3770"],["3771","3772"],["3773","3774"],["3775","3776"],["3777","3778"],["3779","3780"],["3781","3782"],["3783","3784"],["3785","3786"],["3787","3788"],["3789","3790"],["3791","3792"],["3793","3794"],["3795","3796"],["3797","3798"],["3799","3800"],["3801","3802"],["3803","3804"],["3805","3806"],["3807","3808"],["3809","3810"],["3811","3812"],["3813","3814"],["3815","3816"],["3817","3818"],["3819","3820"],["3821","3822"],["3823","3824"],["3825","3826"],["3827","3828"],["3829","3830"],["3831","3832"],["3833","3834"],["3835","3836"],["3837","3838"],["3839","3840"],["3841","3842"],["3843","3844"],["3845","3846"],["3847","3848"],["3849","3850"],["3851","3852"],["3853","3854"],["3855","3856"],["3857","3858"],["3859","3860"],["3861","3862"],["3863","3864"],["3865","3866"],["3867","3868"],["3869","3870"],["3871","3872"],["3873","3874"],["3875","3876"],["3877","3878"],["3879","3880"],["3881","3882"],["3883","3884"],["3885","3886"],["3887","3888"],["3889","3890"],["3891","3892"],["3893","3894"],"no-useless-escape","Unnecessary escape character: \\..","Literal","unnecessaryEscape",["3895","3896"],["3897"],"Unnecessary escape character: \\[.",["3898","3899"],["3900"],["3901","3902"],["3903","3904"],{"messageId":"3905","fix":"3906","desc":"3907"},{"messageId":"3908","fix":"3909","desc":"3910"},{"messageId":"3905","fix":"3911","desc":"3907"},{"messageId":"3908","fix":"3912","desc":"3910"},{"messageId":"3905","fix":"3913","desc":"3907"},{"messageId":"3908","fix":"3914","desc":"3910"},{"messageId":"3905","fix":"3915","desc":"3907"},{"messageId":"3908","fix":"3916","desc":"3910"},{"messageId":"3905","fix":"3917","desc":"3907"},{"messageId":"3908","fix":"3918","desc":"3910"},{"messageId":"3905","fix":"3919","desc":"3907"},{"messageId":"3908","fix":"3920","desc":"3910"},{"messageId":"3905","fix":"3921","desc":"3907"},{"messageId":"3908","fix":"3922","desc":"3910"},{"messageId":"3905","fix":"3923","desc":"3907"},{"messageId":"3908","fix":"3924","desc":"3910"},{"messageId":"3905","fix":"3925","desc":"3907"},{"messageId":"3908","fix":"3926","desc":"3910"},{"messageId":"3905","fix":"3927","desc":"3907"},{"messageId":"3908","fix":"3928","desc":"3910"},{"messageId":"3905","fix":"3929","desc":"3907"},{"messageId":"3908","fix":"3930","desc":"3910"},{"messageId":"3905","fix":"3931","desc":"3907"},{"messageId":"3908","fix":"3932","desc":"3910"},{"messageId":"3905","fix":"3933","desc":"3907"},{"messageId":"3908","fix":"3934","desc":"3910"},{"messageId":"3905","fix":"3935","desc":"3907"},{"messageId":"3908","fix":"3936","desc":"3910"},{"messageId":"3905","fix":"3937","desc":"3907"},{"messageId":"3908","fix":"3938","desc":"3910"},{"messageId":"3905","fix":"3939","desc":"3907"},{"messageId":"3908","fix":"3940","desc":"3910"},{"messageId":"3905","fix":"3941","desc":"3907"},{"messageId":"3908","fix":"3942","desc":"3910"},{"messageId":"3905","fix":"3943","desc":"3907"},{"messageId":"3908","fix":"3944","desc":"3910"},{"messageId":"3905","fix":"3945","desc":"3907"},{"messageId":"3908","fix":"3946","desc":"3910"},{"messageId":"3905","fix":"3947","desc":"3907"},{"messageId":"3908","fix":"3948","desc":"3910"},{"messageId":"3905","fix":"3949","desc":"3907"},{"messageId":"3908","fix":"3950","desc":"3910"},{"messageId":"3905","fix":"3951","desc":"3907"},{"messageId":"3908","fix":"3952","desc":"3910"},{"messageId":"3905","fix":"3953","desc":"3907"},{"messageId":"3908","fix":"3954","desc":"3910"},{"messageId":"3905","fix":"3955","desc":"3907"},{"messageId":"3908","fix":"3956","desc":"3910"},{"messageId":"3905","fix":"3957","desc":"3907"},{"messageId":"3908","fix":"3958","desc":"3910"},{"messageId":"3905","fix":"3959","desc":"3907"},{"messageId":"3908","fix":"3960","desc":"3910"},{"messageId":"3905","fix":"3961","desc":"3907"},{"messageId":"3908","fix":"3962","desc":"3910"},{"messageId":"3905","fix":"3963","desc":"3907"},{"messageId":"3908","fix":"3964","desc":"3910"},{"messageId":"3905","fix":"3965","desc":"3907"},{"messageId":"3908","fix":"3966","desc":"3910"},{"messageId":"3905","fix":"3967","desc":"3907"},{"messageId":"3908","fix":"3968","desc":"3910"},{"messageId":"3905","fix":"3969","desc":"3907"},{"messageId":"3908","fix":"3970","desc":"3910"},{"messageId":"3905","fix":"3971","desc":"3907"},{"messageId":"3908","fix":"3972","desc":"3910"},{"messageId":"3905","fix":"3973","desc":"3907"},{"messageId":"3908","fix":"3974","desc":"3910"},{"messageId":"3905","fix":"3975","desc":"3907"},{"messageId":"3908","fix":"3976","desc":"3910"},{"messageId":"3905","fix":"3977","desc":"3907"},{"messageId":"3908","fix":"3978","desc":"3910"},{"messageId":"3905","fix":"3979","desc":"3907"},{"messageId":"3908","fix":"3980","desc":"3910"},{"messageId":"3905","fix":"3981","desc":"3907"},{"messageId":"3908","fix":"3982","desc":"3910"},{"messageId":"3905","fix":"3983","desc":"3907"},{"messageId":"3908","fix":"3984","desc":"3910"},{"messageId":"3905","fix":"3985","desc":"3907"},{"messageId":"3908","fix":"3986","desc":"3910"},{"messageId":"3905","fix":"3987","desc":"3907"},{"messageId":"3908","fix":"3988","desc":"3910"},{"messageId":"3905","fix":"3989","desc":"3907"},{"messageId":"3908","fix":"3990","desc":"3910"},{"messageId":"3905","fix":"3991","desc":"3907"},{"messageId":"3908","fix":"3992","desc":"3910"},{"messageId":"3905","fix":"3993","desc":"3907"},{"messageId":"3908","fix":"3994","desc":"3910"},{"messageId":"3905","fix":"3995","desc":"3907"},{"messageId":"3908","fix":"3996","desc":"3910"},{"messageId":"3905","fix":"3997","desc":"3907"},{"messageId":"3908","fix":"3998","desc":"3910"},{"messageId":"3905","fix":"3999","desc":"3907"},{"messageId":"3908","fix":"4000","desc":"3910"},{"messageId":"3905","fix":"4001","desc":"3907"},{"messageId":"3908","fix":"4002","desc":"3910"},{"messageId":"3905","fix":"4003","desc":"3907"},{"messageId":"3908","fix":"4004","desc":"3910"},{"messageId":"3905","fix":"4005","desc":"3907"},{"messageId":"3908","fix":"4006","desc":"3910"},{"messageId":"3905","fix":"4007","desc":"3907"},{"messageId":"3908","fix":"4008","desc":"3910"},{"messageId":"3905","fix":"4009","desc":"3907"},{"messageId":"3908","fix":"4010","desc":"3910"},{"messageId":"3905","fix":"4011","desc":"3907"},{"messageId":"3908","fix":"4012","desc":"3910"},{"messageId":"3905","fix":"4013","desc":"3907"},{"messageId":"3908","fix":"4014","desc":"3910"},{"messageId":"3905","fix":"4015","desc":"3907"},{"messageId":"3908","fix":"4016","desc":"3910"},{"messageId":"3905","fix":"4017","desc":"3907"},{"messageId":"3908","fix":"4018","desc":"3910"},{"messageId":"3905","fix":"4019","desc":"3907"},{"messageId":"3908","fix":"4020","desc":"3910"},{"messageId":"3905","fix":"4021","desc":"3907"},{"messageId":"3908","fix":"4022","desc":"3910"},{"messageId":"3905","fix":"4023","desc":"3907"},{"messageId":"3908","fix":"4024","desc":"3910"},{"messageId":"3905","fix":"4025","desc":"3907"},{"messageId":"3908","fix":"4026","desc":"3910"},{"messageId":"3905","fix":"4027","desc":"3907"},{"messageId":"3908","fix":"4028","desc":"3910"},{"messageId":"3905","fix":"4029","desc":"3907"},{"messageId":"3908","fix":"4030","desc":"3910"},{"messageId":"3905","fix":"4031","desc":"3907"},{"messageId":"3908","fix":"4032","desc":"3910"},{"messageId":"3905","fix":"4033","desc":"3907"},{"messageId":"3908","fix":"4034","desc":"3910"},{"messageId":"3905","fix":"4035","desc":"3907"},{"messageId":"3908","fix":"4036","desc":"3910"},{"messageId":"3905","fix":"4037","desc":"3907"},{"messageId":"3908","fix":"4038","desc":"3910"},{"messageId":"3905","fix":"4039","desc":"3907"},{"messageId":"3908","fix":"4040","desc":"3910"},{"messageId":"3905","fix":"4041","desc":"3907"},{"messageId":"3908","fix":"4042","desc":"3910"},{"messageId":"3905","fix":"4043","desc":"3907"},{"messageId":"3908","fix":"4044","desc":"3910"},{"messageId":"3905","fix":"4045","desc":"3907"},{"messageId":"3908","fix":"4046","desc":"3910"},{"messageId":"3905","fix":"4047","desc":"3907"},{"messageId":"3908","fix":"4048","desc":"3910"},{"messageId":"3905","fix":"4049","desc":"3907"},{"messageId":"3908","fix":"4050","desc":"3910"},{"messageId":"3905","fix":"4051","desc":"3907"},{"messageId":"3908","fix":"4052","desc":"3910"},{"messageId":"3905","fix":"4053","desc":"3907"},{"messageId":"3908","fix":"4054","desc":"3910"},{"messageId":"3905","fix":"4055","desc":"3907"},{"messageId":"3908","fix":"4056","desc":"3910"},{"messageId":"3905","fix":"4057","desc":"3907"},{"messageId":"3908","fix":"4058","desc":"3910"},{"messageId":"3905","fix":"4059","desc":"3907"},{"messageId":"3908","fix":"4060","desc":"3910"},{"messageId":"3905","fix":"4061","desc":"3907"},{"messageId":"3908","fix":"4062","desc":"3910"},{"messageId":"3905","fix":"4063","desc":"3907"},{"messageId":"3908","fix":"4064","desc":"3910"},{"messageId":"3905","fix":"4065","desc":"3907"},{"messageId":"3908","fix":"4066","desc":"3910"},{"messageId":"3905","fix":"4067","desc":"3907"},{"messageId":"3908","fix":"4068","desc":"3910"},{"messageId":"3905","fix":"4069","desc":"3907"},{"messageId":"3908","fix":"4070","desc":"3910"},{"messageId":"3905","fix":"4071","desc":"3907"},{"messageId":"3908","fix":"4072","desc":"3910"},{"messageId":"3905","fix":"4073","desc":"3907"},{"messageId":"3908","fix":"4074","desc":"3910"},{"messageId":"3905","fix":"4075","desc":"3907"},{"messageId":"3908","fix":"4076","desc":"3910"},{"messageId":"3905","fix":"4077","desc":"3907"},{"messageId":"3908","fix":"4078","desc":"3910"},{"messageId":"3905","fix":"4079","desc":"3907"},{"messageId":"3908","fix":"4080","desc":"3910"},{"messageId":"3905","fix":"4081","desc":"3907"},{"messageId":"3908","fix":"4082","desc":"3910"},{"messageId":"3905","fix":"4083","desc":"3907"},{"messageId":"3908","fix":"4084","desc":"3910"},{"messageId":"3905","fix":"4085","desc":"3907"},{"messageId":"3908","fix":"4086","desc":"3910"},{"messageId":"3905","fix":"4087","desc":"3907"},{"messageId":"3908","fix":"4088","desc":"3910"},{"messageId":"3905","fix":"4089","desc":"3907"},{"messageId":"3908","fix":"4090","desc":"3910"},{"messageId":"3905","fix":"4091","desc":"3907"},{"messageId":"3908","fix":"4092","desc":"3910"},{"messageId":"3905","fix":"4093","desc":"3907"},{"messageId":"3908","fix":"4094","desc":"3910"},{"messageId":"3905","fix":"4095","desc":"3907"},{"messageId":"3908","fix":"4096","desc":"3910"},{"messageId":"3905","fix":"4097","desc":"3907"},{"messageId":"3908","fix":"4098","desc":"3910"},{"messageId":"3905","fix":"4099","desc":"3907"},{"messageId":"3908","fix":"4100","desc":"3910"},{"messageId":"3905","fix":"4101","desc":"3907"},{"messageId":"3908","fix":"4102","desc":"3910"},{"messageId":"3905","fix":"4103","desc":"3907"},{"messageId":"3908","fix":"4104","desc":"3910"},{"messageId":"3905","fix":"4105","desc":"3907"},{"messageId":"3908","fix":"4106","desc":"3910"},{"messageId":"3905","fix":"4107","desc":"3907"},{"messageId":"3908","fix":"4108","desc":"3910"},{"messageId":"3905","fix":"4109","desc":"3907"},{"messageId":"3908","fix":"4110","desc":"3910"},{"messageId":"3905","fix":"4111","desc":"3907"},{"messageId":"3908","fix":"4112","desc":"3910"},{"messageId":"3905","fix":"4113","desc":"3907"},{"messageId":"3908","fix":"4114","desc":"3910"},{"messageId":"3905","fix":"4115","desc":"3907"},{"messageId":"3908","fix":"4116","desc":"3910"},{"messageId":"3905","fix":"4117","desc":"3907"},{"messageId":"3908","fix":"4118","desc":"3910"},{"messageId":"3905","fix":"4119","desc":"3907"},{"messageId":"3908","fix":"4120","desc":"3910"},{"messageId":"3905","fix":"4121","desc":"3907"},{"messageId":"3908","fix":"4122","desc":"3910"},{"messageId":"3905","fix":"4123","desc":"3907"},{"messageId":"3908","fix":"4124","desc":"3910"},{"messageId":"3905","fix":"4125","desc":"3907"},{"messageId":"3908","fix":"4126","desc":"3910"},{"messageId":"3905","fix":"4127","desc":"3907"},{"messageId":"3908","fix":"4128","desc":"3910"},{"messageId":"3905","fix":"4129","desc":"3907"},{"messageId":"3908","fix":"4130","desc":"3910"},{"messageId":"3905","fix":"4131","desc":"3907"},{"messageId":"3908","fix":"4132","desc":"3910"},{"messageId":"3905","fix":"4133","desc":"3907"},{"messageId":"3908","fix":"4134","desc":"3910"},{"messageId":"3905","fix":"4135","desc":"3907"},{"messageId":"3908","fix":"4136","desc":"3910"},{"messageId":"3905","fix":"4137","desc":"3907"},{"messageId":"3908","fix":"4138","desc":"3910"},{"messageId":"3905","fix":"4139","desc":"3907"},{"messageId":"3908","fix":"4140","desc":"3910"},{"messageId":"3905","fix":"4141","desc":"3907"},{"messageId":"3908","fix":"4142","desc":"3910"},{"messageId":"3905","fix":"4143","desc":"3907"},{"messageId":"3908","fix":"4144","desc":"3910"},{"messageId":"3905","fix":"4145","desc":"3907"},{"messageId":"3908","fix":"4146","desc":"3910"},{"messageId":"3905","fix":"4147","desc":"3907"},{"messageId":"3908","fix":"4148","desc":"3910"},{"messageId":"3905","fix":"4149","desc":"3907"},{"messageId":"3908","fix":"4150","desc":"3910"},{"messageId":"3905","fix":"4151","desc":"3907"},{"messageId":"3908","fix":"4152","desc":"3910"},{"messageId":"3905","fix":"4153","desc":"3907"},{"messageId":"3908","fix":"4154","desc":"3910"},{"messageId":"3905","fix":"4155","desc":"3907"},{"messageId":"3908","fix":"4156","desc":"3910"},{"messageId":"3905","fix":"4157","desc":"3907"},{"messageId":"3908","fix":"4158","desc":"3910"},{"messageId":"3905","fix":"4159","desc":"3907"},{"messageId":"3908","fix":"4160","desc":"3910"},{"messageId":"3905","fix":"4161","desc":"3907"},{"messageId":"3908","fix":"4162","desc":"3910"},{"messageId":"3905","fix":"4163","desc":"3907"},{"messageId":"3908","fix":"4164","desc":"3910"},{"messageId":"3905","fix":"4165","desc":"3907"},{"messageId":"3908","fix":"4166","desc":"3910"},{"messageId":"3905","fix":"4167","desc":"3907"},{"messageId":"3908","fix":"4168","desc":"3910"},{"messageId":"3905","fix":"4169","desc":"3907"},{"messageId":"3908","fix":"4170","desc":"3910"},{"messageId":"3905","fix":"4171","desc":"3907"},{"messageId":"3908","fix":"4172","desc":"3910"},{"messageId":"3905","fix":"4173","desc":"3907"},{"messageId":"3908","fix":"4174","desc":"3910"},{"messageId":"3905","fix":"4175","desc":"3907"},{"messageId":"3908","fix":"4176","desc":"3910"},{"messageId":"3905","fix":"4177","desc":"3907"},{"messageId":"3908","fix":"4178","desc":"3910"},{"messageId":"3905","fix":"4179","desc":"3907"},{"messageId":"3908","fix":"4180","desc":"3910"},{"messageId":"3905","fix":"4181","desc":"3907"},{"messageId":"3908","fix":"4182","desc":"3910"},{"messageId":"3905","fix":"4183","desc":"3907"},{"messageId":"3908","fix":"4184","desc":"3910"},{"messageId":"3905","fix":"4185","desc":"3907"},{"messageId":"3908","fix":"4186","desc":"3910"},{"messageId":"3905","fix":"4187","desc":"3907"},{"messageId":"3908","fix":"4188","desc":"3910"},{"messageId":"3905","fix":"4189","desc":"3907"},{"messageId":"3908","fix":"4190","desc":"3910"},{"messageId":"3905","fix":"4191","desc":"3907"},{"messageId":"3908","fix":"4192","desc":"3910"},{"messageId":"3905","fix":"4193","desc":"3907"},{"messageId":"3908","fix":"4194","desc":"3910"},{"messageId":"3905","fix":"4195","desc":"3907"},{"messageId":"3908","fix":"4196","desc":"3910"},{"messageId":"3905","fix":"4197","desc":"3907"},{"messageId":"3908","fix":"4198","desc":"3910"},{"messageId":"3905","fix":"4199","desc":"3907"},{"messageId":"3908","fix":"4200","desc":"3910"},{"messageId":"3905","fix":"4201","desc":"3907"},{"messageId":"3908","fix":"4202","desc":"3910"},{"messageId":"3905","fix":"4203","desc":"3907"},{"messageId":"3908","fix":"4204","desc":"3910"},{"messageId":"3905","fix":"4205","desc":"3907"},{"messageId":"3908","fix":"4206","desc":"3910"},{"messageId":"3905","fix":"4207","desc":"3907"},{"messageId":"3908","fix":"4208","desc":"3910"},{"messageId":"3905","fix":"4209","desc":"3907"},{"messageId":"3908","fix":"4210","desc":"3910"},{"messageId":"3905","fix":"4211","desc":"3907"},{"messageId":"3908","fix":"4212","desc":"3910"},{"messageId":"3905","fix":"4213","desc":"3907"},{"messageId":"3908","fix":"4214","desc":"3910"},{"messageId":"3905","fix":"4215","desc":"3907"},{"messageId":"3908","fix":"4216","desc":"3910"},{"messageId":"3905","fix":"4217","desc":"3907"},{"messageId":"3908","fix":"4218","desc":"3910"},{"messageId":"3905","fix":"4219","desc":"3907"},{"messageId":"3908","fix":"4220","desc":"3910"},{"messageId":"3905","fix":"4221","desc":"3907"},{"messageId":"3908","fix":"4222","desc":"3910"},{"messageId":"3905","fix":"4223","desc":"3907"},{"messageId":"3908","fix":"4224","desc":"3910"},{"messageId":"3905","fix":"4225","desc":"3907"},{"messageId":"3908","fix":"4226","desc":"3910"},{"messageId":"3905","fix":"4227","desc":"3907"},{"messageId":"3908","fix":"4228","desc":"3910"},{"messageId":"3905","fix":"4229","desc":"3907"},{"messageId":"3908","fix":"4230","desc":"3910"},{"messageId":"3905","fix":"4231","desc":"3907"},{"messageId":"3908","fix":"4232","desc":"3910"},{"messageId":"3905","fix":"4233","desc":"3907"},{"messageId":"3908","fix":"4234","desc":"3910"},{"messageId":"3905","fix":"4235","desc":"3907"},{"messageId":"3908","fix":"4236","desc":"3910"},{"messageId":"3905","fix":"4237","desc":"3907"},{"messageId":"3908","fix":"4238","desc":"3910"},{"messageId":"3905","fix":"4239","desc":"3907"},{"messageId":"3908","fix":"4240","desc":"3910"},{"messageId":"3905","fix":"4241","desc":"3907"},{"messageId":"3908","fix":"4242","desc":"3910"},{"messageId":"3905","fix":"4243","desc":"3907"},{"messageId":"3908","fix":"4244","desc":"3910"},{"messageId":"3905","fix":"4245","desc":"3907"},{"messageId":"3908","fix":"4246","desc":"3910"},{"messageId":"3905","fix":"4247","desc":"3907"},{"messageId":"3908","fix":"4248","desc":"3910"},{"messageId":"3905","fix":"4249","desc":"3907"},{"messageId":"3908","fix":"4250","desc":"3910"},{"messageId":"3905","fix":"4251","desc":"3907"},{"messageId":"3908","fix":"4252","desc":"3910"},{"messageId":"3905","fix":"4253","desc":"3907"},{"messageId":"3908","fix":"4254","desc":"3910"},{"messageId":"3905","fix":"4255","desc":"3907"},{"messageId":"3908","fix":"4256","desc":"3910"},{"messageId":"3905","fix":"4257","desc":"3907"},{"messageId":"3908","fix":"4258","desc":"3910"},{"messageId":"3905","fix":"4259","desc":"3907"},{"messageId":"3908","fix":"4260","desc":"3910"},{"messageId":"3905","fix":"4261","desc":"3907"},{"messageId":"3908","fix":"4262","desc":"3910"},{"messageId":"3905","fix":"4263","desc":"3907"},{"messageId":"3908","fix":"4264","desc":"3910"},{"messageId":"3905","fix":"4265","desc":"3907"},{"messageId":"3908","fix":"4266","desc":"3910"},{"messageId":"3905","fix":"4267","desc":"3907"},{"messageId":"3908","fix":"4268","desc":"3910"},{"messageId":"3905","fix":"4269","desc":"3907"},{"messageId":"3908","fix":"4270","desc":"3910"},{"messageId":"3905","fix":"4271","desc":"3907"},{"messageId":"3908","fix":"4272","desc":"3910"},{"messageId":"3905","fix":"4273","desc":"3907"},{"messageId":"3908","fix":"4274","desc":"3910"},{"messageId":"3905","fix":"4275","desc":"3907"},{"messageId":"3908","fix":"4276","desc":"3910"},{"messageId":"3905","fix":"4277","desc":"3907"},{"messageId":"3908","fix":"4278","desc":"3910"},{"messageId":"3905","fix":"4279","desc":"3907"},{"messageId":"3908","fix":"4280","desc":"3910"},{"messageId":"3905","fix":"4281","desc":"3907"},{"messageId":"3908","fix":"4282","desc":"3910"},{"messageId":"3905","fix":"4283","desc":"3907"},{"messageId":"3908","fix":"4284","desc":"3910"},{"messageId":"3905","fix":"4285","desc":"3907"},{"messageId":"3908","fix":"4286","desc":"3910"},{"messageId":"3905","fix":"4287","desc":"3907"},{"messageId":"3908","fix":"4288","desc":"3910"},{"messageId":"3905","fix":"4289","desc":"3907"},{"messageId":"3908","fix":"4290","desc":"3910"},{"messageId":"3905","fix":"4291","desc":"3907"},{"messageId":"3908","fix":"4292","desc":"3910"},{"messageId":"3905","fix":"4293","desc":"3907"},{"messageId":"3908","fix":"4294","desc":"3910"},{"messageId":"3905","fix":"4295","desc":"3907"},{"messageId":"3908","fix":"4296","desc":"3910"},{"messageId":"3905","fix":"4297","desc":"3907"},{"messageId":"3908","fix":"4298","desc":"3910"},{"messageId":"3905","fix":"4299","desc":"3907"},{"messageId":"3908","fix":"4300","desc":"3910"},{"messageId":"3905","fix":"4301","desc":"3907"},{"messageId":"3908","fix":"4302","desc":"3910"},{"messageId":"3905","fix":"4303","desc":"3907"},{"messageId":"3908","fix":"4304","desc":"3910"},{"messageId":"3905","fix":"4305","desc":"3907"},{"messageId":"3908","fix":"4306","desc":"3910"},{"messageId":"3905","fix":"4307","desc":"3907"},{"messageId":"3908","fix":"4308","desc":"3910"},{"messageId":"3905","fix":"4309","desc":"3907"},{"messageId":"3908","fix":"4310","desc":"3910"},{"messageId":"3905","fix":"4311","desc":"3907"},{"messageId":"3908","fix":"4312","desc":"3910"},{"messageId":"3905","fix":"4313","desc":"3907"},{"messageId":"3908","fix":"4314","desc":"3910"},{"messageId":"3905","fix":"4315","desc":"3907"},{"messageId":"3908","fix":"4316","desc":"3910"},{"messageId":"3905","fix":"4317","desc":"3907"},{"messageId":"3908","fix":"4318","desc":"3910"},{"messageId":"3905","fix":"4319","desc":"3907"},{"messageId":"3908","fix":"4320","desc":"3910"},{"messageId":"3905","fix":"4321","desc":"3907"},{"messageId":"3908","fix":"4322","desc":"3910"},{"messageId":"3905","fix":"4323","desc":"3907"},{"messageId":"3908","fix":"4324","desc":"3910"},{"messageId":"3905","fix":"4325","desc":"3907"},{"messageId":"3908","fix":"4326","desc":"3910"},{"messageId":"3905","fix":"4327","desc":"3907"},{"messageId":"3908","fix":"4328","desc":"3910"},{"messageId":"3905","fix":"4329","desc":"3907"},{"messageId":"3908","fix":"4330","desc":"3910"},{"messageId":"3905","fix":"4331","desc":"3907"},{"messageId":"3908","fix":"4332","desc":"3910"},{"messageId":"3905","fix":"4333","desc":"3907"},{"messageId":"3908","fix":"4334","desc":"3910"},{"messageId":"3905","fix":"4335","desc":"3907"},{"messageId":"3908","fix":"4336","desc":"3910"},{"messageId":"3905","fix":"4337","desc":"3907"},{"messageId":"3908","fix":"4338","desc":"3910"},{"messageId":"3905","fix":"4339","desc":"3907"},{"messageId":"3908","fix":"4340","desc":"3910"},{"messageId":"3905","fix":"4341","desc":"3907"},{"messageId":"3908","fix":"4342","desc":"3910"},{"messageId":"3905","fix":"4343","desc":"3907"},{"messageId":"3908","fix":"4344","desc":"3910"},{"messageId":"3905","fix":"4345","desc":"3907"},{"messageId":"3908","fix":"4346","desc":"3910"},{"messageId":"3905","fix":"4347","desc":"3907"},{"messageId":"3908","fix":"4348","desc":"3910"},{"messageId":"3905","fix":"4349","desc":"3907"},{"messageId":"3908","fix":"4350","desc":"3910"},{"messageId":"3905","fix":"4351","desc":"3907"},{"messageId":"3908","fix":"4352","desc":"3910"},{"messageId":"3905","fix":"4353","desc":"3907"},{"messageId":"3908","fix":"4354","desc":"3910"},{"messageId":"3905","fix":"4355","desc":"3907"},{"messageId":"3908","fix":"4356","desc":"3910"},{"messageId":"3905","fix":"4357","desc":"3907"},{"messageId":"3908","fix":"4358","desc":"3910"},{"messageId":"3905","fix":"4359","desc":"3907"},{"messageId":"3908","fix":"4360","desc":"3910"},{"messageId":"3905","fix":"4361","desc":"3907"},{"messageId":"3908","fix":"4362","desc":"3910"},{"messageId":"3905","fix":"4363","desc":"3907"},{"messageId":"3908","fix":"4364","desc":"3910"},{"messageId":"3905","fix":"4365","desc":"3907"},{"messageId":"3908","fix":"4366","desc":"3910"},{"messageId":"3905","fix":"4367","desc":"3907"},{"messageId":"3908","fix":"4368","desc":"3910"},{"messageId":"3905","fix":"4369","desc":"3907"},{"messageId":"3908","fix":"4370","desc":"3910"},{"messageId":"3905","fix":"4371","desc":"3907"},{"messageId":"3908","fix":"4372","desc":"3910"},{"messageId":"3905","fix":"4373","desc":"3907"},{"messageId":"3908","fix":"4374","desc":"3910"},{"messageId":"3905","fix":"4375","desc":"3907"},{"messageId":"3908","fix":"4376","desc":"3910"},{"messageId":"3905","fix":"4377","desc":"3907"},{"messageId":"3908","fix":"4378","desc":"3910"},{"messageId":"3905","fix":"4379","desc":"3907"},{"messageId":"3908","fix":"4380","desc":"3910"},{"messageId":"3905","fix":"4381","desc":"3907"},{"messageId":"3908","fix":"4382","desc":"3910"},{"messageId":"3905","fix":"4383","desc":"3907"},{"messageId":"3908","fix":"4384","desc":"3910"},{"messageId":"3905","fix":"4385","desc":"3907"},{"messageId":"3908","fix":"4386","desc":"3910"},{"messageId":"3905","fix":"4387","desc":"3907"},{"messageId":"3908","fix":"4388","desc":"3910"},{"messageId":"3905","fix":"4389","desc":"3907"},{"messageId":"3908","fix":"4390","desc":"3910"},{"messageId":"3905","fix":"4391","desc":"3907"},{"messageId":"3908","fix":"4392","desc":"3910"},{"messageId":"3905","fix":"4393","desc":"3907"},{"messageId":"3908","fix":"4394","desc":"3910"},{"messageId":"3905","fix":"4395","desc":"3907"},{"messageId":"3908","fix":"4396","desc":"3910"},{"messageId":"3905","fix":"4397","desc":"3907"},{"messageId":"3908","fix":"4398","desc":"3910"},{"messageId":"3905","fix":"4399","desc":"3907"},{"messageId":"3908","fix":"4400","desc":"3910"},{"messageId":"3905","fix":"4401","desc":"3907"},{"messageId":"3908","fix":"4402","desc":"3910"},{"messageId":"3905","fix":"4403","desc":"3907"},{"messageId":"3908","fix":"4404","desc":"3910"},{"messageId":"3905","fix":"4405","desc":"3907"},{"messageId":"3908","fix":"4406","desc":"3910"},{"messageId":"3905","fix":"4407","desc":"3907"},{"messageId":"3908","fix":"4408","desc":"3910"},{"messageId":"3905","fix":"4409","desc":"3907"},{"messageId":"3908","fix":"4410","desc":"3910"},{"messageId":"3905","fix":"4411","desc":"3907"},{"messageId":"3908","fix":"4412","desc":"3910"},{"messageId":"3905","fix":"4413","desc":"3907"},{"messageId":"3908","fix":"4414","desc":"3910"},{"messageId":"3905","fix":"4415","desc":"3907"},{"messageId":"3908","fix":"4416","desc":"3910"},{"messageId":"3905","fix":"4417","desc":"3907"},{"messageId":"3908","fix":"4418","desc":"3910"},{"messageId":"3905","fix":"4419","desc":"3907"},{"messageId":"3908","fix":"4420","desc":"3910"},{"messageId":"3905","fix":"4421","desc":"3907"},{"messageId":"3908","fix":"4422","desc":"3910"},{"messageId":"3905","fix":"4423","desc":"3907"},{"messageId":"3908","fix":"4424","desc":"3910"},{"messageId":"3905","fix":"4425","desc":"3907"},{"messageId":"3908","fix":"4426","desc":"3910"},{"messageId":"3905","fix":"4427","desc":"3907"},{"messageId":"3908","fix":"4428","desc":"3910"},{"messageId":"3905","fix":"4429","desc":"3907"},{"messageId":"3908","fix":"4430","desc":"3910"},{"messageId":"3905","fix":"4431","desc":"3907"},{"messageId":"3908","fix":"4432","desc":"3910"},{"messageId":"3905","fix":"4433","desc":"3907"},{"messageId":"3908","fix":"4434","desc":"3910"},{"messageId":"3905","fix":"4435","desc":"3907"},{"messageId":"3908","fix":"4436","desc":"3910"},{"messageId":"3905","fix":"4437","desc":"3907"},{"messageId":"3908","fix":"4438","desc":"3910"},{"messageId":"3905","fix":"4439","desc":"3907"},{"messageId":"3908","fix":"4440","desc":"3910"},{"messageId":"3905","fix":"4441","desc":"3907"},{"messageId":"3908","fix":"4442","desc":"3910"},{"messageId":"3905","fix":"4443","desc":"3907"},{"messageId":"3908","fix":"4444","desc":"3910"},{"messageId":"3905","fix":"4445","desc":"3907"},{"messageId":"3908","fix":"4446","desc":"3910"},{"messageId":"3905","fix":"4447","desc":"3907"},{"messageId":"3908","fix":"4448","desc":"3910"},{"messageId":"3905","fix":"4449","desc":"3907"},{"messageId":"3908","fix":"4450","desc":"3910"},{"messageId":"3905","fix":"4451","desc":"3907"},{"messageId":"3908","fix":"4452","desc":"3910"},{"messageId":"3905","fix":"4453","desc":"3907"},{"messageId":"3908","fix":"4454","desc":"3910"},{"messageId":"3905","fix":"4455","desc":"3907"},{"messageId":"3908","fix":"4456","desc":"3910"},{"messageId":"3905","fix":"4457","desc":"3907"},{"messageId":"3908","fix":"4458","desc":"3910"},{"messageId":"3905","fix":"4459","desc":"3907"},{"messageId":"3908","fix":"4460","desc":"3910"},{"messageId":"3905","fix":"4461","desc":"3907"},{"messageId":"3908","fix":"4462","desc":"3910"},{"messageId":"3905","fix":"4463","desc":"3907"},{"messageId":"3908","fix":"4464","desc":"3910"},{"messageId":"3905","fix":"4465","desc":"3907"},{"messageId":"3908","fix":"4466","desc":"3910"},{"messageId":"3905","fix":"4467","desc":"3907"},{"messageId":"3908","fix":"4468","desc":"3910"},{"messageId":"3905","fix":"4469","desc":"3907"},{"messageId":"3908","fix":"4470","desc":"3910"},{"messageId":"3905","fix":"4471","desc":"3907"},{"messageId":"3908","fix":"4472","desc":"3910"},{"messageId":"3905","fix":"4473","desc":"3907"},{"messageId":"3908","fix":"4474","desc":"3910"},{"messageId":"3905","fix":"4475","desc":"3907"},{"messageId":"3908","fix":"4476","desc":"3910"},{"messageId":"3905","fix":"4477","desc":"3907"},{"messageId":"3908","fix":"4478","desc":"3910"},{"messageId":"3905","fix":"4479","desc":"3907"},{"messageId":"3908","fix":"4480","desc":"3910"},{"messageId":"3905","fix":"4481","desc":"3907"},{"messageId":"3908","fix":"4482","desc":"3910"},{"messageId":"3905","fix":"4483","desc":"3907"},{"messageId":"3908","fix":"4484","desc":"3910"},{"messageId":"3905","fix":"4485","desc":"3907"},{"messageId":"3908","fix":"4486","desc":"3910"},{"messageId":"3905","fix":"4487","desc":"3907"},{"messageId":"3908","fix":"4488","desc":"3910"},{"messageId":"3905","fix":"4489","desc":"3907"},{"messageId":"3908","fix":"4490","desc":"3910"},{"messageId":"3905","fix":"4491","desc":"3907"},{"messageId":"3908","fix":"4492","desc":"3910"},{"messageId":"3905","fix":"4493","desc":"3907"},{"messageId":"3908","fix":"4494","desc":"3910"},{"messageId":"3905","fix":"4495","desc":"3907"},{"messageId":"3908","fix":"4496","desc":"3910"},{"messageId":"3905","fix":"4497","desc":"3907"},{"messageId":"3908","fix":"4498","desc":"3910"},{"messageId":"3905","fix":"4499","desc":"3907"},{"messageId":"3908","fix":"4500","desc":"3910"},{"messageId":"3905","fix":"4501","desc":"3907"},{"messageId":"3908","fix":"4502","desc":"3910"},{"messageId":"3905","fix":"4503","desc":"3907"},{"messageId":"3908","fix":"4504","desc":"3910"},{"messageId":"3905","fix":"4505","desc":"3907"},{"messageId":"3908","fix":"4506","desc":"3910"},{"messageId":"3905","fix":"4507","desc":"3907"},{"messageId":"3908","fix":"4508","desc":"3910"},{"messageId":"3905","fix":"4509","desc":"3907"},{"messageId":"3908","fix":"4510","desc":"3910"},{"messageId":"3905","fix":"4511","desc":"3907"},{"messageId":"3908","fix":"4512","desc":"3910"},{"messageId":"3905","fix":"4513","desc":"3907"},{"messageId":"3908","fix":"4514","desc":"3910"},{"messageId":"3905","fix":"4515","desc":"3907"},{"messageId":"3908","fix":"4516","desc":"3910"},{"messageId":"3905","fix":"4517","desc":"3907"},{"messageId":"3908","fix":"4518","desc":"3910"},{"messageId":"3905","fix":"4519","desc":"3907"},{"messageId":"3908","fix":"4520","desc":"3910"},{"messageId":"3905","fix":"4521","desc":"3907"},{"messageId":"3908","fix":"4522","desc":"3910"},{"messageId":"3905","fix":"4523","desc":"3907"},{"messageId":"3908","fix":"4524","desc":"3910"},{"messageId":"3905","fix":"4525","desc":"3907"},{"messageId":"3908","fix":"4526","desc":"3910"},{"messageId":"3905","fix":"4527","desc":"3907"},{"messageId":"3908","fix":"4528","desc":"3910"},{"messageId":"3905","fix":"4529","desc":"3907"},{"messageId":"3908","fix":"4530","desc":"3910"},{"messageId":"3905","fix":"4531","desc":"3907"},{"messageId":"3908","fix":"4532","desc":"3910"},{"messageId":"3905","fix":"4533","desc":"3907"},{"messageId":"3908","fix":"4534","desc":"3910"},{"messageId":"3905","fix":"4535","desc":"3907"},{"messageId":"3908","fix":"4536","desc":"3910"},{"messageId":"3905","fix":"4537","desc":"3907"},{"messageId":"3908","fix":"4538","desc":"3910"},{"messageId":"3905","fix":"4539","desc":"3907"},{"messageId":"3908","fix":"4540","desc":"3910"},{"messageId":"3905","fix":"4541","desc":"3907"},{"messageId":"3908","fix":"4542","desc":"3910"},{"messageId":"3905","fix":"4543","desc":"3907"},{"messageId":"3908","fix":"4544","desc":"3910"},{"messageId":"3905","fix":"4545","desc":"3907"},{"messageId":"3908","fix":"4546","desc":"3910"},{"messageId":"3905","fix":"4547","desc":"3907"},{"messageId":"3908","fix":"4548","desc":"3910"},{"messageId":"3905","fix":"4549","desc":"3907"},{"messageId":"3908","fix":"4550","desc":"3910"},{"messageId":"3905","fix":"4551","desc":"3907"},{"messageId":"3908","fix":"4552","desc":"3910"},{"messageId":"3905","fix":"4553","desc":"3907"},{"messageId":"3908","fix":"4554","desc":"3910"},{"messageId":"3905","fix":"4555","desc":"3907"},{"messageId":"3908","fix":"4556","desc":"3910"},{"messageId":"3905","fix":"4557","desc":"3907"},{"messageId":"3908","fix":"4558","desc":"3910"},{"messageId":"3905","fix":"4559","desc":"3907"},{"messageId":"3908","fix":"4560","desc":"3910"},{"messageId":"3905","fix":"4561","desc":"3907"},{"messageId":"3908","fix":"4562","desc":"3910"},{"messageId":"3905","fix":"4563","desc":"3907"},{"messageId":"3908","fix":"4564","desc":"3910"},{"messageId":"3905","fix":"4565","desc":"3907"},{"messageId":"3908","fix":"4566","desc":"3910"},{"messageId":"3905","fix":"4567","desc":"3907"},{"messageId":"3908","fix":"4568","desc":"3910"},{"messageId":"3905","fix":"4569","desc":"3907"},{"messageId":"3908","fix":"4570","desc":"3910"},{"messageId":"3905","fix":"4571","desc":"3907"},{"messageId":"3908","fix":"4572","desc":"3910"},{"messageId":"3905","fix":"4573","desc":"3907"},{"messageId":"3908","fix":"4574","desc":"3910"},{"messageId":"3905","fix":"4575","desc":"3907"},{"messageId":"3908","fix":"4576","desc":"3910"},{"messageId":"3905","fix":"4577","desc":"3907"},{"messageId":"3908","fix":"4578","desc":"3910"},{"messageId":"3905","fix":"4579","desc":"3907"},{"messageId":"3908","fix":"4580","desc":"3910"},{"messageId":"3905","fix":"4581","desc":"3907"},{"messageId":"3908","fix":"4582","desc":"3910"},{"messageId":"3905","fix":"4583","desc":"3907"},{"messageId":"3908","fix":"4584","desc":"3910"},{"messageId":"3905","fix":"4585","desc":"3907"},{"messageId":"3908","fix":"4586","desc":"3910"},{"messageId":"3905","fix":"4587","desc":"3907"},{"messageId":"3908","fix":"4588","desc":"3910"},{"messageId":"3905","fix":"4589","desc":"3907"},{"messageId":"3908","fix":"4590","desc":"3910"},{"messageId":"3905","fix":"4591","desc":"3907"},{"messageId":"3908","fix":"4592","desc":"3910"},{"messageId":"3905","fix":"4593","desc":"3907"},{"messageId":"3908","fix":"4594","desc":"3910"},{"messageId":"3905","fix":"4595","desc":"3907"},{"messageId":"3908","fix":"4596","desc":"3910"},{"messageId":"3905","fix":"4597","desc":"3907"},{"messageId":"3908","fix":"4598","desc":"3910"},{"messageId":"3905","fix":"4599","desc":"3907"},{"messageId":"3908","fix":"4600","desc":"3910"},{"messageId":"3905","fix":"4601","desc":"3907"},{"messageId":"3908","fix":"4602","desc":"3910"},{"messageId":"3905","fix":"4603","desc":"3907"},{"messageId":"3908","fix":"4604","desc":"3910"},{"messageId":"3905","fix":"4605","desc":"3907"},{"messageId":"3908","fix":"4606","desc":"3910"},{"messageId":"3905","fix":"4607","desc":"3907"},{"messageId":"3908","fix":"4608","desc":"3910"},{"messageId":"3905","fix":"4609","desc":"3907"},{"messageId":"3908","fix":"4610","desc":"3910"},{"messageId":"3905","fix":"4611","desc":"3907"},{"messageId":"3908","fix":"4612","desc":"3910"},{"messageId":"3905","fix":"4613","desc":"3907"},{"messageId":"3908","fix":"4614","desc":"3910"},{"messageId":"3905","fix":"4615","desc":"3907"},{"messageId":"3908","fix":"4616","desc":"3910"},{"messageId":"3905","fix":"4617","desc":"3907"},{"messageId":"3908","fix":"4618","desc":"3910"},{"messageId":"3905","fix":"4619","desc":"3907"},{"messageId":"3908","fix":"4620","desc":"3910"},{"messageId":"3905","fix":"4621","desc":"3907"},{"messageId":"3908","fix":"4622","desc":"3910"},{"messageId":"3905","fix":"4623","desc":"3907"},{"messageId":"3908","fix":"4624","desc":"3910"},{"messageId":"3905","fix":"4625","desc":"3907"},{"messageId":"3908","fix":"4626","desc":"3910"},{"messageId":"3905","fix":"4627","desc":"3907"},{"messageId":"3908","fix":"4628","desc":"3910"},{"messageId":"3905","fix":"4629","desc":"3907"},{"messageId":"3908","fix":"4630","desc":"3910"},{"messageId":"3905","fix":"4631","desc":"3907"},{"messageId":"3908","fix":"4632","desc":"3910"},{"messageId":"3905","fix":"4633","desc":"3907"},{"messageId":"3908","fix":"4634","desc":"3910"},{"messageId":"3905","fix":"4635","desc":"3907"},{"messageId":"3908","fix":"4636","desc":"3910"},{"messageId":"3905","fix":"4637","desc":"3907"},{"messageId":"3908","fix":"4638","desc":"3910"},{"messageId":"3905","fix":"4639","desc":"3907"},{"messageId":"3908","fix":"4640","desc":"3910"},{"messageId":"3905","fix":"4641","desc":"3907"},{"messageId":"3908","fix":"4642","desc":"3910"},{"messageId":"3905","fix":"4643","desc":"3907"},{"messageId":"3908","fix":"4644","desc":"3910"},{"messageId":"3905","fix":"4645","desc":"3907"},{"messageId":"3908","fix":"4646","desc":"3910"},{"messageId":"3905","fix":"4647","desc":"3907"},{"messageId":"3908","fix":"4648","desc":"3910"},{"messageId":"3905","fix":"4649","desc":"3907"},{"messageId":"3908","fix":"4650","desc":"3910"},{"messageId":"3905","fix":"4651","desc":"3907"},{"messageId":"3908","fix":"4652","desc":"3910"},{"messageId":"3905","fix":"4653","desc":"3907"},{"messageId":"3908","fix":"4654","desc":"3910"},{"messageId":"3905","fix":"4655","desc":"3907"},{"messageId":"3908","fix":"4656","desc":"3910"},{"messageId":"3905","fix":"4657","desc":"3907"},{"messageId":"3908","fix":"4658","desc":"3910"},{"messageId":"3905","fix":"4659","desc":"3907"},{"messageId":"3908","fix":"4660","desc":"3910"},{"messageId":"3905","fix":"4661","desc":"3907"},{"messageId":"3908","fix":"4662","desc":"3910"},{"messageId":"3905","fix":"4663","desc":"3907"},{"messageId":"3908","fix":"4664","desc":"3910"},{"messageId":"3905","fix":"4665","desc":"3907"},{"messageId":"3908","fix":"4666","desc":"3910"},{"messageId":"3905","fix":"4667","desc":"3907"},{"messageId":"3908","fix":"4668","desc":"3910"},{"messageId":"3905","fix":"4669","desc":"3907"},{"messageId":"3908","fix":"4670","desc":"3910"},{"messageId":"3905","fix":"4671","desc":"3907"},{"messageId":"3908","fix":"4672","desc":"3910"},{"messageId":"3905","fix":"4673","desc":"3907"},{"messageId":"3908","fix":"4674","desc":"3910"},{"messageId":"3905","fix":"4675","desc":"3907"},{"messageId":"3908","fix":"4676","desc":"3910"},{"messageId":"3905","fix":"4677","desc":"3907"},{"messageId":"3908","fix":"4678","desc":"3910"},{"messageId":"3905","fix":"4679","desc":"3907"},{"messageId":"3908","fix":"4680","desc":"3910"},{"messageId":"3905","fix":"4681","desc":"3907"},{"messageId":"3908","fix":"4682","desc":"3910"},{"messageId":"3905","fix":"4683","desc":"3907"},{"messageId":"3908","fix":"4684","desc":"3910"},{"messageId":"3905","fix":"4685","desc":"3907"},{"messageId":"3908","fix":"4686","desc":"3910"},{"messageId":"3905","fix":"4687","desc":"3907"},{"messageId":"3908","fix":"4688","desc":"3910"},{"messageId":"3905","fix":"4689","desc":"3907"},{"messageId":"3908","fix":"4690","desc":"3910"},{"messageId":"3905","fix":"4691","desc":"3907"},{"messageId":"3908","fix":"4692","desc":"3910"},{"messageId":"3905","fix":"4693","desc":"3907"},{"messageId":"3908","fix":"4694","desc":"3910"},{"messageId":"3905","fix":"4695","desc":"3907"},{"messageId":"3908","fix":"4696","desc":"3910"},{"messageId":"3905","fix":"4697","desc":"3907"},{"messageId":"3908","fix":"4698","desc":"3910"},{"messageId":"3905","fix":"4699","desc":"3907"},{"messageId":"3908","fix":"4700","desc":"3910"},{"messageId":"3905","fix":"4701","desc":"3907"},{"messageId":"3908","fix":"4702","desc":"3910"},{"messageId":"3905","fix":"4703","desc":"3907"},{"messageId":"3908","fix":"4704","desc":"3910"},{"messageId":"3905","fix":"4705","desc":"3907"},{"messageId":"3908","fix":"4706","desc":"3910"},{"messageId":"3905","fix":"4707","desc":"3907"},{"messageId":"3908","fix":"4708","desc":"3910"},{"messageId":"3905","fix":"4709","desc":"3907"},{"messageId":"3908","fix":"4710","desc":"3910"},{"messageId":"3905","fix":"4711","desc":"3907"},{"messageId":"3908","fix":"4712","desc":"3910"},{"messageId":"3905","fix":"4713","desc":"3907"},{"messageId":"3908","fix":"4714","desc":"3910"},{"messageId":"3905","fix":"4715","desc":"3907"},{"messageId":"3908","fix":"4716","desc":"3910"},{"messageId":"3905","fix":"4717","desc":"3907"},{"messageId":"3908","fix":"4718","desc":"3910"},{"messageId":"3905","fix":"4719","desc":"3907"},{"messageId":"3908","fix":"4720","desc":"3910"},{"messageId":"3905","fix":"4721","desc":"3907"},{"messageId":"3908","fix":"4722","desc":"3910"},{"messageId":"3905","fix":"4723","desc":"3907"},{"messageId":"3908","fix":"4724","desc":"3910"},{"messageId":"3905","fix":"4725","desc":"3907"},{"messageId":"3908","fix":"4726","desc":"3910"},{"messageId":"3905","fix":"4727","desc":"3907"},{"messageId":"3908","fix":"4728","desc":"3910"},{"messageId":"3905","fix":"4729","desc":"3907"},{"messageId":"3908","fix":"4730","desc":"3910"},{"messageId":"3905","fix":"4731","desc":"3907"},{"messageId":"3908","fix":"4732","desc":"3910"},{"messageId":"3905","fix":"4733","desc":"3907"},{"messageId":"3908","fix":"4734","desc":"3910"},{"messageId":"3905","fix":"4735","desc":"3907"},{"messageId":"3908","fix":"4736","desc":"3910"},{"messageId":"3905","fix":"4737","desc":"3907"},{"messageId":"3908","fix":"4738","desc":"3910"},{"messageId":"3905","fix":"4739","desc":"3907"},{"messageId":"3908","fix":"4740","desc":"3910"},{"messageId":"3905","fix":"4741","desc":"3907"},{"messageId":"3908","fix":"4742","desc":"3910"},{"messageId":"3905","fix":"4743","desc":"3907"},{"messageId":"3908","fix":"4744","desc":"3910"},{"messageId":"3905","fix":"4745","desc":"3907"},{"messageId":"3908","fix":"4746","desc":"3910"},{"messageId":"3905","fix":"4747","desc":"3907"},{"messageId":"3908","fix":"4748","desc":"3910"},{"messageId":"3905","fix":"4749","desc":"3907"},{"messageId":"3908","fix":"4750","desc":"3910"},{"messageId":"3905","fix":"4751","desc":"3907"},{"messageId":"3908","fix":"4752","desc":"3910"},{"messageId":"3905","fix":"4753","desc":"3907"},{"messageId":"3908","fix":"4754","desc":"3910"},{"messageId":"3905","fix":"4755","desc":"3907"},{"messageId":"3908","fix":"4756","desc":"3910"},{"messageId":"3905","fix":"4757","desc":"3907"},{"messageId":"3908","fix":"4758","desc":"3910"},{"messageId":"3905","fix":"4759","desc":"3907"},{"messageId":"3908","fix":"4760","desc":"3910"},{"messageId":"3905","fix":"4761","desc":"3907"},{"messageId":"3908","fix":"4762","desc":"3910"},{"messageId":"3905","fix":"4763","desc":"3907"},{"messageId":"3908","fix":"4764","desc":"3910"},{"messageId":"3905","fix":"4765","desc":"3907"},{"messageId":"3908","fix":"4766","desc":"3910"},{"messageId":"3905","fix":"4767","desc":"3907"},{"messageId":"3908","fix":"4768","desc":"3910"},{"messageId":"3905","fix":"4769","desc":"3907"},{"messageId":"3908","fix":"4770","desc":"3910"},{"messageId":"3905","fix":"4771","desc":"3907"},{"messageId":"3908","fix":"4772","desc":"3910"},{"messageId":"3905","fix":"4773","desc":"3907"},{"messageId":"3908","fix":"4774","desc":"3910"},{"messageId":"3905","fix":"4775","desc":"3907"},{"messageId":"3908","fix":"4776","desc":"3910"},{"messageId":"3905","fix":"4777","desc":"3907"},{"messageId":"3908","fix":"4778","desc":"3910"},{"messageId":"3905","fix":"4779","desc":"3907"},{"messageId":"3908","fix":"4780","desc":"3910"},{"messageId":"3905","fix":"4781","desc":"3907"},{"messageId":"3908","fix":"4782","desc":"3910"},{"messageId":"3905","fix":"4783","desc":"3907"},{"messageId":"3908","fix":"4784","desc":"3910"},{"messageId":"3905","fix":"4785","desc":"3907"},{"messageId":"3908","fix":"4786","desc":"3910"},{"messageId":"3905","fix":"4787","desc":"3907"},{"messageId":"3908","fix":"4788","desc":"3910"},{"messageId":"3905","fix":"4789","desc":"3907"},{"messageId":"3908","fix":"4790","desc":"3910"},{"messageId":"3905","fix":"4791","desc":"3907"},{"messageId":"3908","fix":"4792","desc":"3910"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"kind":"4793","justification":"4794"},{"messageId":"3905","fix":"4795","desc":"3907"},{"messageId":"3908","fix":"4796","desc":"3910"},{"messageId":"3905","fix":"4797","desc":"3907"},{"messageId":"3908","fix":"4798","desc":"3910"},{"messageId":"3905","fix":"4799","desc":"3907"},{"messageId":"3908","fix":"4800","desc":"3910"},{"messageId":"3905","fix":"4801","desc":"3907"},{"messageId":"3908","fix":"4802","desc":"3910"},{"messageId":"3905","fix":"4803","desc":"3907"},{"messageId":"3908","fix":"4804","desc":"3910"},{"messageId":"3905","fix":"4805","desc":"3907"},{"messageId":"3908","fix":"4806","desc":"3910"},{"messageId":"3905","fix":"4807","desc":"3907"},{"messageId":"3908","fix":"4808","desc":"3910"},{"messageId":"3905","fix":"4809","desc":"3907"},{"messageId":"3908","fix":"4810","desc":"3910"},{"messageId":"3905","fix":"4811","desc":"3907"},{"messageId":"3908","fix":"4812","desc":"3910"},{"messageId":"3905","fix":"4813","desc":"3907"},{"messageId":"3908","fix":"4814","desc":"3910"},{"messageId":"3905","fix":"4815","desc":"3907"},{"messageId":"3908","fix":"4816","desc":"3910"},{"messageId":"3905","fix":"4817","desc":"3907"},{"messageId":"3908","fix":"4818","desc":"3910"},{"messageId":"3905","fix":"4819","desc":"3907"},{"messageId":"3908","fix":"4820","desc":"3910"},{"messageId":"3905","fix":"4821","desc":"3907"},{"messageId":"3908","fix":"4822","desc":"3910"},{"messageId":"3905","fix":"4823","desc":"3907"},{"messageId":"3908","fix":"4824","desc":"3910"},{"messageId":"3905","fix":"4825","desc":"3907"},{"messageId":"3908","fix":"4826","desc":"3910"},{"messageId":"3905","fix":"4827","desc":"3907"},{"messageId":"3908","fix":"4828","desc":"3910"},{"messageId":"3905","fix":"4829","desc":"3907"},{"messageId":"3908","fix":"4830","desc":"3910"},{"messageId":"3905","fix":"4831","desc":"3907"},{"messageId":"3908","fix":"4832","desc":"3910"},{"messageId":"3905","fix":"4833","desc":"3907"},{"messageId":"3908","fix":"4834","desc":"3910"},{"messageId":"3905","fix":"4835","desc":"3907"},{"messageId":"3908","fix":"4836","desc":"3910"},{"messageId":"3905","fix":"4837","desc":"3907"},{"messageId":"3908","fix":"4838","desc":"3910"},{"messageId":"3905","fix":"4839","desc":"3907"},{"messageId":"3908","fix":"4840","desc":"3910"},{"messageId":"3905","fix":"4841","desc":"3907"},{"messageId":"3908","fix":"4842","desc":"3910"},{"messageId":"3905","fix":"4843","desc":"3907"},{"messageId":"3908","fix":"4844","desc":"3910"},{"messageId":"3905","fix":"4845","desc":"3907"},{"messageId":"3908","fix":"4846","desc":"3910"},{"messageId":"3905","fix":"4847","desc":"3907"},{"messageId":"3908","fix":"4848","desc":"3910"},{"messageId":"3905","fix":"4849","desc":"3907"},{"messageId":"3908","fix":"4850","desc":"3910"},{"messageId":"3905","fix":"4851","desc":"3907"},{"messageId":"3908","fix":"4852","desc":"3910"},{"messageId":"3905","fix":"4853","desc":"3907"},{"messageId":"3908","fix":"4854","desc":"3910"},{"messageId":"3905","fix":"4855","desc":"3907"},{"messageId":"3908","fix":"4856","desc":"3910"},{"messageId":"3905","fix":"4857","desc":"3907"},{"messageId":"3908","fix":"4858","desc":"3910"},{"messageId":"3905","fix":"4859","desc":"3907"},{"messageId":"3908","fix":"4860","desc":"3910"},{"messageId":"3905","fix":"4861","desc":"3907"},{"messageId":"3908","fix":"4862","desc":"3910"},{"messageId":"3905","fix":"4863","desc":"3907"},{"messageId":"3908","fix":"4864","desc":"3910"},{"messageId":"3905","fix":"4865","desc":"3907"},{"messageId":"3908","fix":"4866","desc":"3910"},{"messageId":"3905","fix":"4867","desc":"3907"},{"messageId":"3908","fix":"4868","desc":"3910"},{"messageId":"3905","fix":"4869","desc":"3907"},{"messageId":"3908","fix":"4870","desc":"3910"},{"messageId":"3905","fix":"4871","desc":"3907"},{"messageId":"3908","fix":"4872","desc":"3910"},{"messageId":"3905","fix":"4873","desc":"3907"},{"messageId":"3908","fix":"4874","desc":"3910"},{"messageId":"3905","fix":"4875","desc":"3907"},{"messageId":"3908","fix":"4876","desc":"3910"},{"messageId":"3905","fix":"4877","desc":"3907"},{"messageId":"3908","fix":"4878","desc":"3910"},{"messageId":"3905","fix":"4879","desc":"3907"},{"messageId":"3908","fix":"4880","desc":"3910"},{"messageId":"3905","fix":"4881","desc":"3907"},{"messageId":"3908","fix":"4882","desc":"3910"},{"messageId":"3905","fix":"4883","desc":"3907"},{"messageId":"3908","fix":"4884","desc":"3910"},{"kind":"4793","justification":"4794"},{"messageId":"3905","fix":"4885","desc":"3907"},{"messageId":"3908","fix":"4886","desc":"3910"},{"messageId":"3905","fix":"4887","desc":"3907"},{"messageId":"3908","fix":"4888","desc":"3910"},{"messageId":"3905","fix":"4889","desc":"3907"},{"messageId":"3908","fix":"4890","desc":"3910"},{"messageId":"3905","fix":"4891","desc":"3907"},{"messageId":"3908","fix":"4892","desc":"3910"},{"messageId":"3905","fix":"4893","desc":"3907"},{"messageId":"3908","fix":"4894","desc":"3910"},{"messageId":"3905","fix":"4895","desc":"3907"},{"messageId":"3908","fix":"4896","desc":"3910"},{"messageId":"3905","fix":"4897","desc":"3907"},{"messageId":"3908","fix":"4898","desc":"3910"},{"messageId":"3905","fix":"4899","desc":"3907"},{"messageId":"3908","fix":"4900","desc":"3910"},{"messageId":"3905","fix":"4901","desc":"3907"},{"messageId":"3908","fix":"4902","desc":"3910"},{"messageId":"3905","fix":"4903","desc":"3907"},{"messageId":"3908","fix":"4904","desc":"3910"},{"messageId":"3905","fix":"4905","desc":"3907"},{"messageId":"3908","fix":"4906","desc":"3910"},{"messageId":"3905","fix":"4907","desc":"3907"},{"messageId":"3908","fix":"4908","desc":"3910"},{"messageId":"3905","fix":"4909","desc":"3907"},{"messageId":"3908","fix":"4910","desc":"3910"},{"messageId":"3905","fix":"4911","desc":"3907"},{"messageId":"3908","fix":"4912","desc":"3910"},{"messageId":"3905","fix":"4913","desc":"3907"},{"messageId":"3908","fix":"4914","desc":"3910"},{"messageId":"3905","fix":"4915","desc":"3907"},{"messageId":"3908","fix":"4916","desc":"3910"},{"messageId":"3905","fix":"4917","desc":"3907"},{"messageId":"3908","fix":"4918","desc":"3910"},{"messageId":"3905","fix":"4919","desc":"3907"},{"messageId":"3908","fix":"4920","desc":"3910"},{"messageId":"3905","fix":"4921","desc":"3907"},{"messageId":"3908","fix":"4922","desc":"3910"},{"messageId":"3905","fix":"4923","desc":"3907"},{"messageId":"3908","fix":"4924","desc":"3910"},{"messageId":"3905","fix":"4925","desc":"3907"},{"messageId":"3908","fix":"4926","desc":"3910"},{"messageId":"3905","fix":"4927","desc":"3907"},{"messageId":"3908","fix":"4928","desc":"3910"},{"messageId":"3905","fix":"4929","desc":"3907"},{"messageId":"3908","fix":"4930","desc":"3910"},{"messageId":"3905","fix":"4931","desc":"3907"},{"messageId":"3908","fix":"4932","desc":"3910"},{"messageId":"3905","fix":"4933","desc":"3907"},{"messageId":"3908","fix":"4934","desc":"3910"},{"messageId":"3905","fix":"4935","desc":"3907"},{"messageId":"3908","fix":"4936","desc":"3910"},{"messageId":"3905","fix":"4937","desc":"3907"},{"messageId":"3908","fix":"4938","desc":"3910"},{"messageId":"3905","fix":"4939","desc":"3907"},{"messageId":"3908","fix":"4940","desc":"3910"},{"messageId":"3905","fix":"4941","desc":"3907"},{"messageId":"3908","fix":"4942","desc":"3910"},{"messageId":"3905","fix":"4943","desc":"3907"},{"messageId":"3908","fix":"4944","desc":"3910"},{"messageId":"3905","fix":"4945","desc":"3907"},{"messageId":"3908","fix":"4946","desc":"3910"},{"messageId":"3905","fix":"4947","desc":"3907"},{"messageId":"3908","fix":"4948","desc":"3910"},{"messageId":"3905","fix":"4949","desc":"3907"},{"messageId":"3908","fix":"4950","desc":"3910"},{"messageId":"3905","fix":"4951","desc":"3907"},{"messageId":"3908","fix":"4952","desc":"3910"},{"messageId":"3905","fix":"4953","desc":"3907"},{"messageId":"3908","fix":"4954","desc":"3910"},{"messageId":"3905","fix":"4955","desc":"3907"},{"messageId":"3908","fix":"4956","desc":"3910"},{"messageId":"3905","fix":"4957","desc":"3907"},{"messageId":"3908","fix":"4958","desc":"3910"},{"messageId":"3905","fix":"4959","desc":"3907"},{"messageId":"3908","fix":"4960","desc":"3910"},{"messageId":"3905","fix":"4961","desc":"3907"},{"messageId":"3908","fix":"4962","desc":"3910"},{"messageId":"3905","fix":"4963","desc":"3907"},{"messageId":"3908","fix":"4964","desc":"3910"},{"messageId":"3905","fix":"4965","desc":"3907"},{"messageId":"3908","fix":"4966","desc":"3910"},{"messageId":"3905","fix":"4967","desc":"3907"},{"messageId":"3908","fix":"4968","desc":"3910"},{"messageId":"3905","fix":"4969","desc":"3907"},{"messageId":"3908","fix":"4970","desc":"3910"},{"messageId":"3905","fix":"4971","desc":"3907"},{"messageId":"3908","fix":"4972","desc":"3910"},{"messageId":"3905","fix":"4973","desc":"3907"},{"messageId":"3908","fix":"4974","desc":"3910"},{"messageId":"3905","fix":"4975","desc":"3907"},{"messageId":"3908","fix":"4976","desc":"3910"},{"messageId":"3905","fix":"4977","desc":"3907"},{"messageId":"3908","fix":"4978","desc":"3910"},{"messageId":"3905","fix":"4979","desc":"3907"},{"messageId":"3908","fix":"4980","desc":"3910"},{"messageId":"3905","fix":"4981","desc":"3907"},{"messageId":"3908","fix":"4982","desc":"3910"},{"messageId":"3905","fix":"4983","desc":"3907"},{"messageId":"3908","fix":"4984","desc":"3910"},{"messageId":"3905","fix":"4985","desc":"3907"},{"messageId":"3908","fix":"4986","desc":"3910"},{"messageId":"3905","fix":"4987","desc":"3907"},{"messageId":"3908","fix":"4988","desc":"3910"},{"messageId":"3905","fix":"4989","desc":"3907"},{"messageId":"3908","fix":"4990","desc":"3910"},{"messageId":"3905","fix":"4991","desc":"3907"},{"messageId":"3908","fix":"4992","desc":"3910"},{"messageId":"3905","fix":"4993","desc":"3907"},{"messageId":"3908","fix":"4994","desc":"3910"},{"messageId":"3905","fix":"4995","desc":"3907"},{"messageId":"3908","fix":"4996","desc":"3910"},{"messageId":"3905","fix":"4997","desc":"3907"},{"messageId":"3908","fix":"4998","desc":"3910"},{"messageId":"3905","fix":"4999","desc":"3907"},{"messageId":"3908","fix":"5000","desc":"3910"},{"messageId":"3905","fix":"5001","desc":"3907"},{"messageId":"3908","fix":"5002","desc":"3910"},{"messageId":"3905","fix":"5003","desc":"3907"},{"messageId":"3908","fix":"5004","desc":"3910"},{"messageId":"3905","fix":"5005","desc":"3907"},{"messageId":"3908","fix":"5006","desc":"3910"},{"messageId":"3905","fix":"5007","desc":"3907"},{"messageId":"3908","fix":"5008","desc":"3910"},{"messageId":"3905","fix":"5009","desc":"3907"},{"messageId":"3908","fix":"5010","desc":"3910"},{"messageId":"3905","fix":"5011","desc":"3907"},{"messageId":"3908","fix":"5012","desc":"3910"},{"messageId":"3905","fix":"5013","desc":"3907"},{"messageId":"3908","fix":"5014","desc":"3910"},{"messageId":"3905","fix":"5015","desc":"3907"},{"messageId":"3908","fix":"5016","desc":"3910"},{"messageId":"3905","fix":"5017","desc":"3907"},{"messageId":"3908","fix":"5018","desc":"3910"},{"messageId":"3905","fix":"5019","desc":"3907"},{"messageId":"3908","fix":"5020","desc":"3910"},{"messageId":"3905","fix":"5021","desc":"3907"},{"messageId":"3908","fix":"5022","desc":"3910"},{"messageId":"3905","fix":"5023","desc":"3907"},{"messageId":"3908","fix":"5024","desc":"3910"},{"messageId":"3905","fix":"5025","desc":"3907"},{"messageId":"3908","fix":"5026","desc":"3910"},{"messageId":"3905","fix":"5027","desc":"3907"},{"messageId":"3908","fix":"5028","desc":"3910"},{"messageId":"3905","fix":"5029","desc":"3907"},{"messageId":"3908","fix":"5030","desc":"3910"},{"messageId":"3905","fix":"5031","desc":"3907"},{"messageId":"3908","fix":"5032","desc":"3910"},{"messageId":"3905","fix":"5033","desc":"3907"},{"messageId":"3908","fix":"5034","desc":"3910"},{"messageId":"3905","fix":"5035","desc":"3907"},{"messageId":"3908","fix":"5036","desc":"3910"},{"messageId":"3905","fix":"5037","desc":"3907"},{"messageId":"3908","fix":"5038","desc":"3910"},{"messageId":"3905","fix":"5039","desc":"3907"},{"messageId":"3908","fix":"5040","desc":"3910"},{"messageId":"3905","fix":"5041","desc":"3907"},{"messageId":"3908","fix":"5042","desc":"3910"},{"messageId":"3905","fix":"5043","desc":"3907"},{"messageId":"3908","fix":"5044","desc":"3910"},{"messageId":"3905","fix":"5045","desc":"3907"},{"messageId":"3908","fix":"5046","desc":"3910"},{"messageId":"3905","fix":"5047","desc":"3907"},{"messageId":"3908","fix":"5048","desc":"3910"},{"messageId":"3905","fix":"5049","desc":"3907"},{"messageId":"3908","fix":"5050","desc":"3910"},{"messageId":"3905","fix":"5051","desc":"3907"},{"messageId":"3908","fix":"5052","desc":"3910"},{"messageId":"3905","fix":"5053","desc":"3907"},{"messageId":"3908","fix":"5054","desc":"3910"},{"messageId":"3905","fix":"5055","desc":"3907"},{"messageId":"3908","fix":"5056","desc":"3910"},{"messageId":"3905","fix":"5057","desc":"3907"},{"messageId":"3908","fix":"5058","desc":"3910"},{"messageId":"3905","fix":"5059","desc":"3907"},{"messageId":"3908","fix":"5060","desc":"3910"},{"messageId":"3905","fix":"5061","desc":"3907"},{"messageId":"3908","fix":"5062","desc":"3910"},{"messageId":"3905","fix":"5063","desc":"3907"},{"messageId":"3908","fix":"5064","desc":"3910"},{"messageId":"3905","fix":"5065","desc":"3907"},{"messageId":"3908","fix":"5066","desc":"3910"},{"messageId":"3905","fix":"5067","desc":"3907"},{"messageId":"3908","fix":"5068","desc":"3910"},{"messageId":"3905","fix":"5069","desc":"3907"},{"messageId":"3908","fix":"5070","desc":"3910"},{"messageId":"3905","fix":"5071","desc":"3907"},{"messageId":"3908","fix":"5072","desc":"3910"},{"messageId":"3905","fix":"5073","desc":"3907"},{"messageId":"3908","fix":"5074","desc":"3910"},{"messageId":"3905","fix":"5075","desc":"3907"},{"messageId":"3908","fix":"5076","desc":"3910"},{"messageId":"3905","fix":"5077","desc":"3907"},{"messageId":"3908","fix":"5078","desc":"3910"},{"messageId":"3905","fix":"5079","desc":"3907"},{"messageId":"3908","fix":"5080","desc":"3910"},{"messageId":"3905","fix":"5081","desc":"3907"},{"messageId":"3908","fix":"5082","desc":"3910"},{"messageId":"3905","fix":"5083","desc":"3907"},{"messageId":"3908","fix":"5084","desc":"3910"},{"messageId":"3905","fix":"5085","desc":"3907"},{"messageId":"3908","fix":"5086","desc":"3910"},{"messageId":"3905","fix":"5087","desc":"3907"},{"messageId":"3908","fix":"5088","desc":"3910"},{"messageId":"3905","fix":"5089","desc":"3907"},{"messageId":"3908","fix":"5090","desc":"3910"},{"messageId":"3905","fix":"5091","desc":"3907"},{"messageId":"3908","fix":"5092","desc":"3910"},{"messageId":"3905","fix":"5093","desc":"3907"},{"messageId":"3908","fix":"5094","desc":"3910"},{"messageId":"3905","fix":"5095","desc":"3907"},{"messageId":"3908","fix":"5096","desc":"3910"},{"messageId":"3905","fix":"5097","desc":"3907"},{"messageId":"3908","fix":"5098","desc":"3910"},{"messageId":"3905","fix":"5099","desc":"3907"},{"messageId":"3908","fix":"5100","desc":"3910"},{"messageId":"3905","fix":"5101","desc":"3907"},{"messageId":"3908","fix":"5102","desc":"3910"},{"messageId":"3905","fix":"5103","desc":"3907"},{"messageId":"3908","fix":"5104","desc":"3910"},{"messageId":"3905","fix":"5105","desc":"3907"},{"messageId":"3908","fix":"5106","desc":"3910"},{"messageId":"3905","fix":"5107","desc":"3907"},{"messageId":"3908","fix":"5108","desc":"3910"},{"messageId":"3905","fix":"5109","desc":"3907"},{"messageId":"3908","fix":"5110","desc":"3910"},{"messageId":"3905","fix":"5111","desc":"3907"},{"messageId":"3908","fix":"5112","desc":"3910"},{"messageId":"3905","fix":"5113","desc":"3907"},{"messageId":"3908","fix":"5114","desc":"3910"},{"messageId":"3905","fix":"5115","desc":"3907"},{"messageId":"3908","fix":"5116","desc":"3910"},{"messageId":"3905","fix":"5117","desc":"3907"},{"messageId":"3908","fix":"5118","desc":"3910"},{"messageId":"3905","fix":"5119","desc":"3907"},{"messageId":"3908","fix":"5120","desc":"3910"},{"messageId":"3905","fix":"5121","desc":"3907"},{"messageId":"3908","fix":"5122","desc":"3910"},{"messageId":"3905","fix":"5123","desc":"3907"},{"messageId":"3908","fix":"5124","desc":"3910"},{"messageId":"3905","fix":"5125","desc":"3907"},{"messageId":"3908","fix":"5126","desc":"3910"},{"messageId":"3905","fix":"5127","desc":"3907"},{"messageId":"3908","fix":"5128","desc":"3910"},{"messageId":"3905","fix":"5129","desc":"3907"},{"messageId":"3908","fix":"5130","desc":"3910"},{"messageId":"3905","fix":"5131","desc":"3907"},{"messageId":"3908","fix":"5132","desc":"3910"},{"messageId":"3905","fix":"5133","desc":"3907"},{"messageId":"3908","fix":"5134","desc":"3910"},{"messageId":"3905","fix":"5135","desc":"3907"},{"messageId":"3908","fix":"5136","desc":"3910"},{"messageId":"3905","fix":"5137","desc":"3907"},{"messageId":"3908","fix":"5138","desc":"3910"},{"messageId":"3905","fix":"5139","desc":"3907"},{"messageId":"3908","fix":"5140","desc":"3910"},{"messageId":"3905","fix":"5141","desc":"3907"},{"messageId":"3908","fix":"5142","desc":"3910"},{"messageId":"3905","fix":"5143","desc":"3907"},{"messageId":"3908","fix":"5144","desc":"3910"},{"messageId":"3905","fix":"5145","desc":"3907"},{"messageId":"3908","fix":"5146","desc":"3910"},{"messageId":"3905","fix":"5147","desc":"3907"},{"messageId":"3908","fix":"5148","desc":"3910"},{"messageId":"3905","fix":"5149","desc":"3907"},{"messageId":"3908","fix":"5150","desc":"3910"},{"messageId":"3905","fix":"5151","desc":"3907"},{"messageId":"3908","fix":"5152","desc":"3910"},{"messageId":"3905","fix":"5153","desc":"3907"},{"messageId":"3908","fix":"5154","desc":"3910"},{"messageId":"3905","fix":"5155","desc":"3907"},{"messageId":"3908","fix":"5156","desc":"3910"},{"messageId":"3905","fix":"5157","desc":"3907"},{"messageId":"3908","fix":"5158","desc":"3910"},{"messageId":"3905","fix":"5159","desc":"3907"},{"messageId":"3908","fix":"5160","desc":"3910"},{"messageId":"3905","fix":"5161","desc":"3907"},{"messageId":"3908","fix":"5162","desc":"3910"},{"messageId":"3905","fix":"5163","desc":"3907"},{"messageId":"3908","fix":"5164","desc":"3910"},{"messageId":"3905","fix":"5165","desc":"3907"},{"messageId":"3908","fix":"5166","desc":"3910"},{"messageId":"3905","fix":"5167","desc":"3907"},{"messageId":"3908","fix":"5168","desc":"3910"},{"messageId":"3905","fix":"5169","desc":"3907"},{"messageId":"3908","fix":"5170","desc":"3910"},{"messageId":"3905","fix":"5171","desc":"3907"},{"messageId":"3908","fix":"5172","desc":"3910"},{"messageId":"3905","fix":"5173","desc":"3907"},{"messageId":"3908","fix":"5174","desc":"3910"},{"messageId":"3905","fix":"5175","desc":"3907"},{"messageId":"3908","fix":"5176","desc":"3910"},{"messageId":"3905","fix":"5177","desc":"3907"},{"messageId":"3908","fix":"5178","desc":"3910"},{"messageId":"3905","fix":"5179","desc":"3907"},{"messageId":"3908","fix":"5180","desc":"3910"},{"messageId":"3905","fix":"5181","desc":"3907"},{"messageId":"3908","fix":"5182","desc":"3910"},{"messageId":"3905","fix":"5183","desc":"3907"},{"messageId":"3908","fix":"5184","desc":"3910"},{"messageId":"3905","fix":"5185","desc":"3907"},{"messageId":"3908","fix":"5186","desc":"3910"},{"messageId":"3905","fix":"5187","desc":"3907"},{"messageId":"3908","fix":"5188","desc":"3910"},{"messageId":"3905","fix":"5189","desc":"3907"},{"messageId":"3908","fix":"5190","desc":"3910"},{"messageId":"3905","fix":"5191","desc":"3907"},{"messageId":"3908","fix":"5192","desc":"3910"},{"messageId":"3905","fix":"5193","desc":"3907"},{"messageId":"3908","fix":"5194","desc":"3910"},{"messageId":"3905","fix":"5195","desc":"3907"},{"messageId":"3908","fix":"5196","desc":"3910"},{"messageId":"3905","fix":"5197","desc":"3907"},{"messageId":"3908","fix":"5198","desc":"3910"},{"messageId":"3905","fix":"5199","desc":"3907"},{"messageId":"3908","fix":"5200","desc":"3910"},{"messageId":"3905","fix":"5201","desc":"3907"},{"messageId":"3908","fix":"5202","desc":"3910"},{"messageId":"3905","fix":"5203","desc":"3907"},{"messageId":"3908","fix":"5204","desc":"3910"},{"messageId":"3905","fix":"5205","desc":"3907"},{"messageId":"3908","fix":"5206","desc":"3910"},{"messageId":"3905","fix":"5207","desc":"3907"},{"messageId":"3908","fix":"5208","desc":"3910"},{"messageId":"3905","fix":"5209","desc":"3907"},{"messageId":"3908","fix":"5210","desc":"3910"},{"messageId":"3905","fix":"5211","desc":"3907"},{"messageId":"3908","fix":"5212","desc":"3910"},{"messageId":"3905","fix":"5213","desc":"3907"},{"messageId":"3908","fix":"5214","desc":"3910"},{"messageId":"3905","fix":"5215","desc":"3907"},{"messageId":"3908","fix":"5216","desc":"3910"},{"messageId":"3905","fix":"5217","desc":"3907"},{"messageId":"3908","fix":"5218","desc":"3910"},{"messageId":"3905","fix":"5219","desc":"3907"},{"messageId":"3908","fix":"5220","desc":"3910"},{"messageId":"3905","fix":"5221","desc":"3907"},{"messageId":"3908","fix":"5222","desc":"3910"},{"messageId":"3905","fix":"5223","desc":"3907"},{"messageId":"3908","fix":"5224","desc":"3910"},{"messageId":"3905","fix":"5225","desc":"3907"},{"messageId":"3908","fix":"5226","desc":"3910"},{"messageId":"3905","fix":"5227","desc":"3907"},{"messageId":"3908","fix":"5228","desc":"3910"},{"messageId":"3905","fix":"5229","desc":"3907"},{"messageId":"3908","fix":"5230","desc":"3910"},{"messageId":"3905","fix":"5231","desc":"3907"},{"messageId":"3908","fix":"5232","desc":"3910"},{"messageId":"3905","fix":"5233","desc":"3907"},{"messageId":"3908","fix":"5234","desc":"3910"},{"messageId":"3905","fix":"5235","desc":"3907"},{"messageId":"3908","fix":"5236","desc":"3910"},{"messageId":"3905","fix":"5237","desc":"3907"},{"messageId":"3908","fix":"5238","desc":"3910"},{"messageId":"3905","fix":"5239","desc":"3907"},{"messageId":"3908","fix":"5240","desc":"3910"},{"messageId":"3905","fix":"5241","desc":"3907"},{"messageId":"3908","fix":"5242","desc":"3910"},{"messageId":"3905","fix":"5243","desc":"3907"},{"messageId":"3908","fix":"5244","desc":"3910"},{"messageId":"3905","fix":"5245","desc":"3907"},{"messageId":"3908","fix":"5246","desc":"3910"},{"messageId":"3905","fix":"5247","desc":"3907"},{"messageId":"3908","fix":"5248","desc":"3910"},{"messageId":"3905","fix":"5249","desc":"3907"},{"messageId":"3908","fix":"5250","desc":"3910"},{"messageId":"3905","fix":"5251","desc":"3907"},{"messageId":"3908","fix":"5252","desc":"3910"},{"messageId":"3905","fix":"5253","desc":"3907"},{"messageId":"3908","fix":"5254","desc":"3910"},{"messageId":"5255","fix":"5256","desc":"5257"},{"messageId":"5258","fix":"5259","desc":"5260"},{"kind":"4793","justification":"4794"},{"messageId":"5255","fix":"5261","desc":"5257"},{"messageId":"5258","fix":"5262","desc":"5260"},{"kind":"4793","justification":"4794"},{"messageId":"3905","fix":"5263","desc":"3907"},{"messageId":"3908","fix":"5264","desc":"3910"},{"messageId":"3905","fix":"5265","desc":"3907"},{"messageId":"3908","fix":"5266","desc":"3910"},"suggestUnknown",{"range":"5267","text":"5268"},"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct.","suggestNever",{"range":"5269","text":"5270"},"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of.",{"range":"5271","text":"5268"},{"range":"5272","text":"5270"},{"range":"5273","text":"5268"},{"range":"5274","text":"5270"},{"range":"5275","text":"5268"},{"range":"5276","text":"5270"},{"range":"5277","text":"5268"},{"range":"5278","text":"5270"},{"range":"5279","text":"5268"},{"range":"5280","text":"5270"},{"range":"5281","text":"5268"},{"range":"5282","text":"5270"},{"range":"5283","text":"5268"},{"range":"5284","text":"5270"},{"range":"5285","text":"5268"},{"range":"5286","text":"5270"},{"range":"5287","text":"5268"},{"range":"5288","text":"5270"},{"range":"5289","text":"5268"},{"range":"5290","text":"5270"},{"range":"5291","text":"5268"},{"range":"5292","text":"5270"},{"range":"5293","text":"5268"},{"range":"5294","text":"5270"},{"range":"5295","text":"5268"},{"range":"5296","text":"5270"},{"range":"5297","text":"5268"},{"range":"5298","text":"5270"},{"range":"5299","text":"5268"},{"range":"5300","text":"5270"},{"range":"5301","text":"5268"},{"range":"5302","text":"5270"},{"range":"5303","text":"5268"},{"range":"5304","text":"5270"},{"range":"5305","text":"5268"},{"range":"5306","text":"5270"},{"range":"5307","text":"5268"},{"range":"5308","text":"5270"},{"range":"5309","text":"5268"},{"range":"5310","text":"5270"},{"range":"5311","text":"5268"},{"range":"5312","text":"5270"},{"range":"5313","text":"5268"},{"range":"5314","text":"5270"},{"range":"5315","text":"5268"},{"range":"5316","text":"5270"},{"range":"5317","text":"5268"},{"range":"5318","text":"5270"},{"range":"5319","text":"5268"},{"range":"5320","text":"5270"},{"range":"5321","text":"5268"},{"range":"5322","text":"5270"},{"range":"5323","text":"5268"},{"range":"5324","text":"5270"},{"range":"5325","text":"5268"},{"range":"5326","text":"5270"},{"range":"5327","text":"5268"},{"range":"5328","text":"5270"},{"range":"5329","text":"5268"},{"range":"5330","text":"5270"},{"range":"5331","text":"5268"},{"range":"5332","text":"5270"},{"range":"5333","text":"5268"},{"range":"5334","text":"5270"},{"range":"5335","text":"5268"},{"range":"5336","text":"5270"},{"range":"5337","text":"5268"},{"range":"5338","text":"5270"},{"range":"5339","text":"5268"},{"range":"5340","text":"5270"},{"range":"5341","text":"5268"},{"range":"5342","text":"5270"},{"range":"5343","text":"5268"},{"range":"5344","text":"5270"},{"range":"5345","text":"5268"},{"range":"5346","text":"5270"},{"range":"5347","text":"5268"},{"range":"5348","text":"5270"},{"range":"5349","text":"5268"},{"range":"5350","text":"5270"},{"range":"5351","text":"5268"},{"range":"5352","text":"5270"},{"range":"5353","text":"5268"},{"range":"5354","text":"5270"},{"range":"5355","text":"5268"},{"range":"5356","text":"5270"},{"range":"5357","text":"5268"},{"range":"5358","text":"5270"},{"range":"5359","text":"5268"},{"range":"5360","text":"5270"},{"range":"5361","text":"5268"},{"range":"5362","text":"5270"},{"range":"5363","text":"5268"},{"range":"5364","text":"5270"},{"range":"5365","text":"5268"},{"range":"5366","text":"5270"},{"range":"5367","text":"5268"},{"range":"5368","text":"5270"},{"range":"5369","text":"5268"},{"range":"5370","text":"5270"},{"range":"5371","text":"5268"},{"range":"5372","text":"5270"},{"range":"5373","text":"5268"},{"range":"5374","text":"5270"},{"range":"5375","text":"5268"},{"range":"5376","text":"5270"},{"range":"5377","text":"5268"},{"range":"5378","text":"5270"},{"range":"5379","text":"5268"},{"range":"5380","text":"5270"},{"range":"5381","text":"5268"},{"range":"5382","text":"5270"},{"range":"5383","text":"5268"},{"range":"5384","text":"5270"},{"range":"5385","text":"5268"},{"range":"5386","text":"5270"},{"range":"5387","text":"5268"},{"range":"5388","text":"5270"},{"range":"5389","text":"5268"},{"range":"5390","text":"5270"},{"range":"5391","text":"5268"},{"range":"5392","text":"5270"},{"range":"5393","text":"5268"},{"range":"5394","text":"5270"},{"range":"5395","text":"5268"},{"range":"5396","text":"5270"},{"range":"5397","text":"5268"},{"range":"5398","text":"5270"},{"range":"5399","text":"5268"},{"range":"5400","text":"5270"},{"range":"5401","text":"5268"},{"range":"5402","text":"5270"},{"range":"5403","text":"5268"},{"range":"5404","text":"5270"},{"range":"5405","text":"5268"},{"range":"5406","text":"5270"},{"range":"5407","text":"5268"},{"range":"5408","text":"5270"},{"range":"5409","text":"5268"},{"range":"5410","text":"5270"},{"range":"5411","text":"5268"},{"range":"5412","text":"5270"},{"range":"5413","text":"5268"},{"range":"5414","text":"5270"},{"range":"5415","text":"5268"},{"range":"5416","text":"5270"},{"range":"5417","text":"5268"},{"range":"5418","text":"5270"},{"range":"5419","text":"5268"},{"range":"5420","text":"5270"},{"range":"5421","text":"5268"},{"range":"5422","text":"5270"},{"range":"5423","text":"5268"},{"range":"5424","text":"5270"},{"range":"5425","text":"5268"},{"range":"5426","text":"5270"},{"range":"5427","text":"5268"},{"range":"5428","text":"5270"},{"range":"5429","text":"5268"},{"range":"5430","text":"5270"},{"range":"5431","text":"5268"},{"range":"5432","text":"5270"},{"range":"5433","text":"5268"},{"range":"5434","text":"5270"},{"range":"5435","text":"5268"},{"range":"5436","text":"5270"},{"range":"5437","text":"5268"},{"range":"5438","text":"5270"},{"range":"5439","text":"5268"},{"range":"5440","text":"5270"},{"range":"5441","text":"5268"},{"range":"5442","text":"5270"},{"range":"5443","text":"5268"},{"range":"5444","text":"5270"},{"range":"5445","text":"5268"},{"range":"5446","text":"5270"},{"range":"5447","text":"5268"},{"range":"5448","text":"5270"},{"range":"5449","text":"5268"},{"range":"5450","text":"5270"},{"range":"5451","text":"5268"},{"range":"5452","text":"5270"},{"range":"5453","text":"5268"},{"range":"5454","text":"5270"},{"range":"5455","text":"5268"},{"range":"5456","text":"5270"},{"range":"5457","text":"5268"},{"range":"5458","text":"5270"},{"range":"5459","text":"5268"},{"range":"5460","text":"5270"},{"range":"5461","text":"5268"},{"range":"5462","text":"5270"},{"range":"5463","text":"5268"},{"range":"5464","text":"5270"},{"range":"5465","text":"5268"},{"range":"5466","text":"5270"},{"range":"5467","text":"5268"},{"range":"5468","text":"5270"},{"range":"5469","text":"5268"},{"range":"5470","text":"5270"},{"range":"5471","text":"5268"},{"range":"5472","text":"5270"},{"range":"5473","text":"5268"},{"range":"5474","text":"5270"},{"range":"5475","text":"5268"},{"range":"5476","text":"5270"},{"range":"5477","text":"5268"},{"range":"5478","text":"5270"},{"range":"5479","text":"5268"},{"range":"5480","text":"5270"},{"range":"5481","text":"5268"},{"range":"5482","text":"5270"},{"range":"5483","text":"5268"},{"range":"5484","text":"5270"},{"range":"5485","text":"5268"},{"range":"5486","text":"5270"},{"range":"5487","text":"5268"},{"range":"5488","text":"5270"},{"range":"5489","text":"5268"},{"range":"5490","text":"5270"},{"range":"5491","text":"5268"},{"range":"5492","text":"5270"},{"range":"5493","text":"5268"},{"range":"5494","text":"5270"},{"range":"5495","text":"5268"},{"range":"5496","text":"5270"},{"range":"5497","text":"5268"},{"range":"5498","text":"5270"},{"range":"5499","text":"5268"},{"range":"5500","text":"5270"},{"range":"5501","text":"5268"},{"range":"5502","text":"5270"},{"range":"5503","text":"5268"},{"range":"5504","text":"5270"},{"range":"5505","text":"5268"},{"range":"5506","text":"5270"},{"range":"5507","text":"5268"},{"range":"5508","text":"5270"},{"range":"5509","text":"5268"},{"range":"5510","text":"5270"},{"range":"5511","text":"5268"},{"range":"5512","text":"5270"},{"range":"5513","text":"5268"},{"range":"5514","text":"5270"},{"range":"5515","text":"5268"},{"range":"5516","text":"5270"},{"range":"5517","text":"5268"},{"range":"5518","text":"5270"},{"range":"5519","text":"5268"},{"range":"5520","text":"5270"},{"range":"5521","text":"5268"},{"range":"5522","text":"5270"},{"range":"5523","text":"5268"},{"range":"5524","text":"5270"},{"range":"5525","text":"5268"},{"range":"5526","text":"5270"},{"range":"5527","text":"5268"},{"range":"5528","text":"5270"},{"range":"5529","text":"5268"},{"range":"5530","text":"5270"},{"range":"5531","text":"5268"},{"range":"5532","text":"5270"},{"range":"5533","text":"5268"},{"range":"5534","text":"5270"},{"range":"5535","text":"5268"},{"range":"5536","text":"5270"},{"range":"5537","text":"5268"},{"range":"5538","text":"5270"},{"range":"5539","text":"5268"},{"range":"5540","text":"5270"},{"range":"5541","text":"5268"},{"range":"5542","text":"5270"},{"range":"5543","text":"5268"},{"range":"5544","text":"5270"},{"range":"5545","text":"5268"},{"range":"5546","text":"5270"},{"range":"5547","text":"5268"},{"range":"5548","text":"5270"},{"range":"5549","text":"5268"},{"range":"5550","text":"5270"},{"range":"5551","text":"5268"},{"range":"5552","text":"5270"},{"range":"5553","text":"5268"},{"range":"5554","text":"5270"},{"range":"5555","text":"5268"},{"range":"5556","text":"5270"},{"range":"5557","text":"5268"},{"range":"5558","text":"5270"},{"range":"5559","text":"5268"},{"range":"5560","text":"5270"},{"range":"5561","text":"5268"},{"range":"5562","text":"5270"},{"range":"5563","text":"5268"},{"range":"5564","text":"5270"},{"range":"5565","text":"5268"},{"range":"5566","text":"5270"},{"range":"5567","text":"5268"},{"range":"5568","text":"5270"},{"range":"5569","text":"5268"},{"range":"5570","text":"5270"},{"range":"5571","text":"5268"},{"range":"5572","text":"5270"},{"range":"5573","text":"5268"},{"range":"5574","text":"5270"},{"range":"5575","text":"5268"},{"range":"5576","text":"5270"},{"range":"5577","text":"5268"},{"range":"5578","text":"5270"},{"range":"5579","text":"5268"},{"range":"5580","text":"5270"},{"range":"5581","text":"5268"},{"range":"5582","text":"5270"},{"range":"5583","text":"5268"},{"range":"5584","text":"5270"},{"range":"5585","text":"5268"},{"range":"5586","text":"5270"},{"range":"5587","text":"5268"},{"range":"5588","text":"5270"},{"range":"5589","text":"5268"},{"range":"5590","text":"5270"},{"range":"5591","text":"5268"},{"range":"5592","text":"5270"},{"range":"5593","text":"5268"},{"range":"5594","text":"5270"},{"range":"5595","text":"5268"},{"range":"5596","text":"5270"},{"range":"5597","text":"5268"},{"range":"5598","text":"5270"},{"range":"5599","text":"5268"},{"range":"5600","text":"5270"},{"range":"5601","text":"5268"},{"range":"5602","text":"5270"},{"range":"5603","text":"5268"},{"range":"5604","text":"5270"},{"range":"5605","text":"5268"},{"range":"5606","text":"5270"},{"range":"5607","text":"5268"},{"range":"5608","text":"5270"},{"range":"5609","text":"5268"},{"range":"5610","text":"5270"},{"range":"5611","text":"5268"},{"range":"5612","text":"5270"},{"range":"5613","text":"5268"},{"range":"5614","text":"5270"},{"range":"5615","text":"5268"},{"range":"5616","text":"5270"},{"range":"5617","text":"5268"},{"range":"5618","text":"5270"},{"range":"5619","text":"5268"},{"range":"5620","text":"5270"},{"range":"5621","text":"5268"},{"range":"5622","text":"5270"},{"range":"5623","text":"5268"},{"range":"5624","text":"5270"},{"range":"5625","text":"5268"},{"range":"5626","text":"5270"},{"range":"5627","text":"5268"},{"range":"5628","text":"5270"},{"range":"5629","text":"5268"},{"range":"5630","text":"5270"},{"range":"5631","text":"5268"},{"range":"5632","text":"5270"},{"range":"5633","text":"5268"},{"range":"5634","text":"5270"},{"range":"5635","text":"5268"},{"range":"5636","text":"5270"},{"range":"5637","text":"5268"},{"range":"5638","text":"5270"},{"range":"5639","text":"5268"},{"range":"5640","text":"5270"},{"range":"5641","text":"5268"},{"range":"5642","text":"5270"},{"range":"5643","text":"5268"},{"range":"5644","text":"5270"},{"range":"5645","text":"5268"},{"range":"5646","text":"5270"},{"range":"5647","text":"5268"},{"range":"5648","text":"5270"},{"range":"5649","text":"5268"},{"range":"5650","text":"5270"},{"range":"5651","text":"5268"},{"range":"5652","text":"5270"},{"range":"5653","text":"5268"},{"range":"5654","text":"5270"},{"range":"5655","text":"5268"},{"range":"5656","text":"5270"},{"range":"5657","text":"5268"},{"range":"5658","text":"5270"},{"range":"5659","text":"5268"},{"range":"5660","text":"5270"},{"range":"5661","text":"5268"},{"range":"5662","text":"5270"},{"range":"5663","text":"5268"},{"range":"5664","text":"5270"},{"range":"5665","text":"5268"},{"range":"5666","text":"5270"},{"range":"5667","text":"5268"},{"range":"5668","text":"5270"},{"range":"5669","text":"5268"},{"range":"5670","text":"5270"},{"range":"5671","text":"5268"},{"range":"5672","text":"5270"},{"range":"5673","text":"5268"},{"range":"5674","text":"5270"},{"range":"5675","text":"5268"},{"range":"5676","text":"5270"},{"range":"5677","text":"5268"},{"range":"5678","text":"5270"},{"range":"5679","text":"5268"},{"range":"5680","text":"5270"},{"range":"5681","text":"5268"},{"range":"5682","text":"5270"},{"range":"5683","text":"5268"},{"range":"5684","text":"5270"},{"range":"5685","text":"5268"},{"range":"5686","text":"5270"},{"range":"5687","text":"5268"},{"range":"5688","text":"5270"},{"range":"5689","text":"5268"},{"range":"5690","text":"5270"},{"range":"5691","text":"5268"},{"range":"5692","text":"5270"},{"range":"5693","text":"5268"},{"range":"5694","text":"5270"},{"range":"5695","text":"5268"},{"range":"5696","text":"5270"},{"range":"5697","text":"5268"},{"range":"5698","text":"5270"},{"range":"5699","text":"5268"},{"range":"5700","text":"5270"},{"range":"5701","text":"5268"},{"range":"5702","text":"5270"},{"range":"5703","text":"5268"},{"range":"5704","text":"5270"},{"range":"5705","text":"5268"},{"range":"5706","text":"5270"},{"range":"5707","text":"5268"},{"range":"5708","text":"5270"},{"range":"5709","text":"5268"},{"range":"5710","text":"5270"},{"range":"5711","text":"5268"},{"range":"5712","text":"5270"},{"range":"5713","text":"5268"},{"range":"5714","text":"5270"},{"range":"5715","text":"5268"},{"range":"5716","text":"5270"},{"range":"5717","text":"5268"},{"range":"5718","text":"5270"},{"range":"5719","text":"5268"},{"range":"5720","text":"5270"},{"range":"5721","text":"5268"},{"range":"5722","text":"5270"},{"range":"5723","text":"5268"},{"range":"5724","text":"5270"},{"range":"5725","text":"5268"},{"range":"5726","text":"5270"},{"range":"5727","text":"5268"},{"range":"5728","text":"5270"},{"range":"5729","text":"5268"},{"range":"5730","text":"5270"},{"range":"5731","text":"5268"},{"range":"5732","text":"5270"},{"range":"5733","text":"5268"},{"range":"5734","text":"5270"},{"range":"5735","text":"5268"},{"range":"5736","text":"5270"},{"range":"5737","text":"5268"},{"range":"5738","text":"5270"},{"range":"5739","text":"5268"},{"range":"5740","text":"5270"},{"range":"5741","text":"5268"},{"range":"5742","text":"5270"},{"range":"5743","text":"5268"},{"range":"5744","text":"5270"},{"range":"5745","text":"5268"},{"range":"5746","text":"5270"},{"range":"5747","text":"5268"},{"range":"5748","text":"5270"},{"range":"5749","text":"5268"},{"range":"5750","text":"5270"},{"range":"5751","text":"5268"},{"range":"5752","text":"5270"},{"range":"5753","text":"5268"},{"range":"5754","text":"5270"},{"range":"5755","text":"5268"},{"range":"5756","text":"5270"},{"range":"5757","text":"5268"},{"range":"5758","text":"5270"},{"range":"5759","text":"5268"},{"range":"5760","text":"5270"},{"range":"5761","text":"5268"},{"range":"5762","text":"5270"},{"range":"5763","text":"5268"},{"range":"5764","text":"5270"},{"range":"5765","text":"5268"},{"range":"5766","text":"5270"},{"range":"5767","text":"5268"},{"range":"5768","text":"5270"},{"range":"5769","text":"5268"},{"range":"5770","text":"5270"},{"range":"5771","text":"5268"},{"range":"5772","text":"5270"},{"range":"5773","text":"5268"},{"range":"5774","text":"5270"},{"range":"5775","text":"5268"},{"range":"5776","text":"5270"},{"range":"5777","text":"5268"},{"range":"5778","text":"5270"},{"range":"5779","text":"5268"},{"range":"5780","text":"5270"},{"range":"5781","text":"5268"},{"range":"5782","text":"5270"},{"range":"5783","text":"5268"},{"range":"5784","text":"5270"},{"range":"5785","text":"5268"},{"range":"5786","text":"5270"},{"range":"5787","text":"5268"},{"range":"5788","text":"5270"},{"range":"5789","text":"5268"},{"range":"5790","text":"5270"},{"range":"5791","text":"5268"},{"range":"5792","text":"5270"},{"range":"5793","text":"5268"},{"range":"5794","text":"5270"},{"range":"5795","text":"5268"},{"range":"5796","text":"5270"},{"range":"5797","text":"5268"},{"range":"5798","text":"5270"},{"range":"5799","text":"5268"},{"range":"5800","text":"5270"},{"range":"5801","text":"5268"},{"range":"5802","text":"5270"},{"range":"5803","text":"5268"},{"range":"5804","text":"5270"},{"range":"5805","text":"5268"},{"range":"5806","text":"5270"},{"range":"5807","text":"5268"},{"range":"5808","text":"5270"},{"range":"5809","text":"5268"},{"range":"5810","text":"5270"},{"range":"5811","text":"5268"},{"range":"5812","text":"5270"},{"range":"5813","text":"5268"},{"range":"5814","text":"5270"},{"range":"5815","text":"5268"},{"range":"5816","text":"5270"},{"range":"5817","text":"5268"},{"range":"5818","text":"5270"},{"range":"5819","text":"5268"},{"range":"5820","text":"5270"},{"range":"5821","text":"5268"},{"range":"5822","text":"5270"},{"range":"5823","text":"5268"},{"range":"5824","text":"5270"},{"range":"5825","text":"5268"},{"range":"5826","text":"5270"},{"range":"5827","text":"5268"},{"range":"5828","text":"5270"},{"range":"5829","text":"5268"},{"range":"5830","text":"5270"},{"range":"5831","text":"5268"},{"range":"5832","text":"5270"},{"range":"5833","text":"5268"},{"range":"5834","text":"5270"},{"range":"5835","text":"5268"},{"range":"5836","text":"5270"},{"range":"5837","text":"5268"},{"range":"5838","text":"5270"},{"range":"5839","text":"5268"},{"range":"5840","text":"5270"},{"range":"5841","text":"5268"},{"range":"5842","text":"5270"},{"range":"5843","text":"5268"},{"range":"5844","text":"5270"},{"range":"5845","text":"5268"},{"range":"5846","text":"5270"},{"range":"5847","text":"5268"},{"range":"5848","text":"5270"},{"range":"5849","text":"5268"},{"range":"5850","text":"5270"},{"range":"5851","text":"5268"},{"range":"5852","text":"5270"},{"range":"5853","text":"5268"},{"range":"5854","text":"5270"},{"range":"5855","text":"5268"},{"range":"5856","text":"5270"},{"range":"5857","text":"5268"},{"range":"5858","text":"5270"},{"range":"5859","text":"5268"},{"range":"5860","text":"5270"},{"range":"5861","text":"5268"},{"range":"5862","text":"5270"},{"range":"5863","text":"5268"},{"range":"5864","text":"5270"},{"range":"5865","text":"5268"},{"range":"5866","text":"5270"},{"range":"5867","text":"5268"},{"range":"5868","text":"5270"},{"range":"5869","text":"5268"},{"range":"5870","text":"5270"},{"range":"5871","text":"5268"},{"range":"5872","text":"5270"},{"range":"5873","text":"5268"},{"range":"5874","text":"5270"},{"range":"5875","text":"5268"},{"range":"5876","text":"5270"},{"range":"5877","text":"5268"},{"range":"5878","text":"5270"},{"range":"5879","text":"5268"},{"range":"5880","text":"5270"},{"range":"5881","text":"5268"},{"range":"5882","text":"5270"},{"range":"5883","text":"5268"},{"range":"5884","text":"5270"},{"range":"5885","text":"5268"},{"range":"5886","text":"5270"},{"range":"5887","text":"5268"},{"range":"5888","text":"5270"},{"range":"5889","text":"5268"},{"range":"5890","text":"5270"},{"range":"5891","text":"5268"},{"range":"5892","text":"5270"},{"range":"5893","text":"5268"},{"range":"5894","text":"5270"},{"range":"5895","text":"5268"},{"range":"5896","text":"5270"},{"range":"5897","text":"5268"},{"range":"5898","text":"5270"},{"range":"5899","text":"5268"},{"range":"5900","text":"5270"},{"range":"5901","text":"5268"},{"range":"5902","text":"5270"},{"range":"5903","text":"5268"},{"range":"5904","text":"5270"},{"range":"5905","text":"5268"},{"range":"5906","text":"5270"},{"range":"5907","text":"5268"},{"range":"5908","text":"5270"},{"range":"5909","text":"5268"},{"range":"5910","text":"5270"},{"range":"5911","text":"5268"},{"range":"5912","text":"5270"},{"range":"5913","text":"5268"},{"range":"5914","text":"5270"},{"range":"5915","text":"5268"},{"range":"5916","text":"5270"},{"range":"5917","text":"5268"},{"range":"5918","text":"5270"},{"range":"5919","text":"5268"},{"range":"5920","text":"5270"},{"range":"5921","text":"5268"},{"range":"5922","text":"5270"},{"range":"5923","text":"5268"},{"range":"5924","text":"5270"},{"range":"5925","text":"5268"},{"range":"5926","text":"5270"},{"range":"5927","text":"5268"},{"range":"5928","text":"5270"},{"range":"5929","text":"5268"},{"range":"5930","text":"5270"},{"range":"5931","text":"5268"},{"range":"5932","text":"5270"},{"range":"5933","text":"5268"},{"range":"5934","text":"5270"},{"range":"5935","text":"5268"},{"range":"5936","text":"5270"},{"range":"5937","text":"5268"},{"range":"5938","text":"5270"},{"range":"5939","text":"5268"},{"range":"5940","text":"5270"},{"range":"5941","text":"5268"},{"range":"5942","text":"5270"},{"range":"5943","text":"5268"},{"range":"5944","text":"5270"},{"range":"5945","text":"5268"},{"range":"5946","text":"5270"},{"range":"5947","text":"5268"},{"range":"5948","text":"5270"},{"range":"5949","text":"5268"},{"range":"5950","text":"5270"},{"range":"5951","text":"5268"},{"range":"5952","text":"5270"},{"range":"5953","text":"5268"},{"range":"5954","text":"5270"},{"range":"5955","text":"5268"},{"range":"5956","text":"5270"},{"range":"5957","text":"5268"},{"range":"5958","text":"5270"},{"range":"5959","text":"5268"},{"range":"5960","text":"5270"},{"range":"5961","text":"5268"},{"range":"5962","text":"5270"},{"range":"5963","text":"5268"},{"range":"5964","text":"5270"},{"range":"5965","text":"5268"},{"range":"5966","text":"5270"},{"range":"5967","text":"5268"},{"range":"5968","text":"5270"},{"range":"5969","text":"5268"},{"range":"5970","text":"5270"},{"range":"5971","text":"5268"},{"range":"5972","text":"5270"},{"range":"5973","text":"5268"},{"range":"5974","text":"5270"},{"range":"5975","text":"5268"},{"range":"5976","text":"5270"},{"range":"5977","text":"5268"},{"range":"5978","text":"5270"},{"range":"5979","text":"5268"},{"range":"5980","text":"5270"},{"range":"5981","text":"5268"},{"range":"5982","text":"5270"},{"range":"5983","text":"5268"},{"range":"5984","text":"5270"},{"range":"5985","text":"5268"},{"range":"5986","text":"5270"},{"range":"5987","text":"5268"},{"range":"5988","text":"5270"},{"range":"5989","text":"5268"},{"range":"5990","text":"5270"},{"range":"5991","text":"5268"},{"range":"5992","text":"5270"},{"range":"5993","text":"5268"},{"range":"5994","text":"5270"},{"range":"5995","text":"5268"},{"range":"5996","text":"5270"},{"range":"5997","text":"5268"},{"range":"5998","text":"5270"},{"range":"5999","text":"5268"},{"range":"6000","text":"5270"},{"range":"6001","text":"5268"},{"range":"6002","text":"5270"},{"range":"6003","text":"5268"},{"range":"6004","text":"5270"},{"range":"6005","text":"5268"},{"range":"6006","text":"5270"},{"range":"6007","text":"5268"},{"range":"6008","text":"5270"},{"range":"6009","text":"5268"},{"range":"6010","text":"5270"},{"range":"6011","text":"5268"},{"range":"6012","text":"5270"},{"range":"6013","text":"5268"},{"range":"6014","text":"5270"},{"range":"6015","text":"5268"},{"range":"6016","text":"5270"},{"range":"6017","text":"5268"},{"range":"6018","text":"5270"},{"range":"6019","text":"5268"},{"range":"6020","text":"5270"},{"range":"6021","text":"5268"},{"range":"6022","text":"5270"},{"range":"6023","text":"5268"},{"range":"6024","text":"5270"},{"range":"6025","text":"5268"},{"range":"6026","text":"5270"},{"range":"6027","text":"5268"},{"range":"6028","text":"5270"},{"range":"6029","text":"5268"},{"range":"6030","text":"5270"},{"range":"6031","text":"5268"},{"range":"6032","text":"5270"},{"range":"6033","text":"5268"},{"range":"6034","text":"5270"},{"range":"6035","text":"5268"},{"range":"6036","text":"5270"},{"range":"6037","text":"5268"},{"range":"6038","text":"5270"},{"range":"6039","text":"5268"},{"range":"6040","text":"5270"},{"range":"6041","text":"5268"},{"range":"6042","text":"5270"},{"range":"6043","text":"5268"},{"range":"6044","text":"5270"},{"range":"6045","text":"5268"},{"range":"6046","text":"5270"},{"range":"6047","text":"5268"},{"range":"6048","text":"5270"},{"range":"6049","text":"5268"},{"range":"6050","text":"5270"},{"range":"6051","text":"5268"},{"range":"6052","text":"5270"},{"range":"6053","text":"5268"},{"range":"6054","text":"5270"},{"range":"6055","text":"5268"},{"range":"6056","text":"5270"},{"range":"6057","text":"5268"},{"range":"6058","text":"5270"},{"range":"6059","text":"5268"},{"range":"6060","text":"5270"},{"range":"6061","text":"5268"},{"range":"6062","text":"5270"},{"range":"6063","text":"5268"},{"range":"6064","text":"5270"},{"range":"6065","text":"5268"},{"range":"6066","text":"5270"},{"range":"6067","text":"5268"},{"range":"6068","text":"5270"},{"range":"6069","text":"5268"},{"range":"6070","text":"5270"},{"range":"6071","text":"5268"},{"range":"6072","text":"5270"},{"range":"6073","text":"5268"},{"range":"6074","text":"5270"},{"range":"6075","text":"5268"},{"range":"6076","text":"5270"},{"range":"6077","text":"5268"},{"range":"6078","text":"5270"},{"range":"6079","text":"5268"},{"range":"6080","text":"5270"},{"range":"6081","text":"5268"},{"range":"6082","text":"5270"},{"range":"6083","text":"5268"},{"range":"6084","text":"5270"},{"range":"6085","text":"5268"},{"range":"6086","text":"5270"},{"range":"6087","text":"5268"},{"range":"6088","text":"5270"},{"range":"6089","text":"5268"},{"range":"6090","text":"5270"},{"range":"6091","text":"5268"},{"range":"6092","text":"5270"},{"range":"6093","text":"5268"},{"range":"6094","text":"5270"},{"range":"6095","text":"5268"},{"range":"6096","text":"5270"},{"range":"6097","text":"5268"},{"range":"6098","text":"5270"},{"range":"6099","text":"5268"},{"range":"6100","text":"5270"},{"range":"6101","text":"5268"},{"range":"6102","text":"5270"},{"range":"6103","text":"5268"},{"range":"6104","text":"5270"},{"range":"6105","text":"5268"},{"range":"6106","text":"5270"},{"range":"6107","text":"5268"},{"range":"6108","text":"5270"},{"range":"6109","text":"5268"},{"range":"6110","text":"5270"},{"range":"6111","text":"5268"},{"range":"6112","text":"5270"},{"range":"6113","text":"5268"},{"range":"6114","text":"5270"},{"range":"6115","text":"5268"},{"range":"6116","text":"5270"},{"range":"6117","text":"5268"},{"range":"6118","text":"5270"},{"range":"6119","text":"5268"},{"range":"6120","text":"5270"},{"range":"6121","text":"5268"},{"range":"6122","text":"5270"},{"range":"6123","text":"5268"},{"range":"6124","text":"5270"},{"range":"6125","text":"5268"},{"range":"6126","text":"5270"},{"range":"6127","text":"5268"},{"range":"6128","text":"5270"},{"range":"6129","text":"5268"},{"range":"6130","text":"5270"},{"range":"6131","text":"5268"},{"range":"6132","text":"5270"},{"range":"6133","text":"5268"},{"range":"6134","text":"5270"},{"range":"6135","text":"5268"},{"range":"6136","text":"5270"},{"range":"6137","text":"5268"},{"range":"6138","text":"5270"},{"range":"6139","text":"5268"},{"range":"6140","text":"5270"},{"range":"6141","text":"5268"},{"range":"6142","text":"5270"},{"range":"6143","text":"5268"},{"range":"6144","text":"5270"},{"range":"6145","text":"5268"},{"range":"6146","text":"5270"},{"range":"6147","text":"5268"},{"range":"6148","text":"5270"},{"range":"6149","text":"5268"},{"range":"6150","text":"5270"},{"range":"6151","text":"5268"},{"range":"6152","text":"5270"},"directive","",{"range":"6153","text":"5268"},{"range":"6154","text":"5270"},{"range":"6155","text":"5268"},{"range":"6156","text":"5270"},{"range":"6157","text":"5268"},{"range":"6158","text":"5270"},{"range":"6159","text":"5268"},{"range":"6160","text":"5270"},{"range":"6161","text":"5268"},{"range":"6162","text":"5270"},{"range":"6163","text":"5268"},{"range":"6164","text":"5270"},{"range":"6165","text":"5268"},{"range":"6166","text":"5270"},{"range":"6167","text":"5268"},{"range":"6168","text":"5270"},{"range":"6169","text":"5268"},{"range":"6170","text":"5270"},{"range":"6171","text":"5268"},{"range":"6172","text":"5270"},{"range":"6173","text":"5268"},{"range":"6174","text":"5270"},{"range":"6175","text":"5268"},{"range":"6176","text":"5270"},{"range":"6177","text":"5268"},{"range":"6178","text":"5270"},{"range":"6179","text":"5268"},{"range":"6180","text":"5270"},{"range":"6181","text":"5268"},{"range":"6182","text":"5270"},{"range":"6183","text":"5268"},{"range":"6184","text":"5270"},{"range":"6185","text":"5268"},{"range":"6186","text":"5270"},{"range":"6187","text":"5268"},{"range":"6188","text":"5270"},{"range":"6189","text":"5268"},{"range":"6190","text":"5270"},{"range":"6191","text":"5268"},{"range":"6192","text":"5270"},{"range":"6193","text":"5268"},{"range":"6194","text":"5270"},{"range":"6195","text":"5268"},{"range":"6196","text":"5270"},{"range":"6197","text":"5268"},{"range":"6198","text":"5270"},{"range":"6199","text":"5268"},{"range":"6200","text":"5270"},{"range":"6201","text":"5268"},{"range":"6202","text":"5270"},{"range":"6203","text":"5268"},{"range":"6204","text":"5270"},{"range":"6205","text":"5268"},{"range":"6206","text":"5270"},{"range":"6207","text":"5268"},{"range":"6208","text":"5270"},{"range":"6209","text":"5268"},{"range":"6210","text":"5270"},{"range":"6211","text":"5268"},{"range":"6212","text":"5270"},{"range":"6213","text":"5268"},{"range":"6214","text":"5270"},{"range":"6215","text":"5268"},{"range":"6216","text":"5270"},{"range":"6217","text":"5268"},{"range":"6218","text":"5270"},{"range":"6219","text":"5268"},{"range":"6220","text":"5270"},{"range":"6221","text":"5268"},{"range":"6222","text":"5270"},{"range":"6223","text":"5268"},{"range":"6224","text":"5270"},{"range":"6225","text":"5268"},{"range":"6226","text":"5270"},{"range":"6227","text":"5268"},{"range":"6228","text":"5270"},{"range":"6229","text":"5268"},{"range":"6230","text":"5270"},{"range":"6231","text":"5268"},{"range":"6232","text":"5270"},{"range":"6233","text":"5268"},{"range":"6234","text":"5270"},{"range":"6235","text":"5268"},{"range":"6236","text":"5270"},{"range":"6237","text":"5268"},{"range":"6238","text":"5270"},{"range":"6239","text":"5268"},{"range":"6240","text":"5270"},{"range":"6241","text":"5268"},{"range":"6242","text":"5270"},{"range":"6243","text":"5268"},{"range":"6244","text":"5270"},{"range":"6245","text":"5268"},{"range":"6246","text":"5270"},{"range":"6247","text":"5268"},{"range":"6248","text":"5270"},{"range":"6249","text":"5268"},{"range":"6250","text":"5270"},{"range":"6251","text":"5268"},{"range":"6252","text":"5270"},{"range":"6253","text":"5268"},{"range":"6254","text":"5270"},{"range":"6255","text":"5268"},{"range":"6256","text":"5270"},{"range":"6257","text":"5268"},{"range":"6258","text":"5270"},{"range":"6259","text":"5268"},{"range":"6260","text":"5270"},{"range":"6261","text":"5268"},{"range":"6262","text":"5270"},{"range":"6263","text":"5268"},{"range":"6264","text":"5270"},{"range":"6265","text":"5268"},{"range":"6266","text":"5270"},{"range":"6267","text":"5268"},{"range":"6268","text":"5270"},{"range":"6269","text":"5268"},{"range":"6270","text":"5270"},{"range":"6271","text":"5268"},{"range":"6272","text":"5270"},{"range":"6273","text":"5268"},{"range":"6274","text":"5270"},{"range":"6275","text":"5268"},{"range":"6276","text":"5270"},{"range":"6277","text":"5268"},{"range":"6278","text":"5270"},{"range":"6279","text":"5268"},{"range":"6280","text":"5270"},{"range":"6281","text":"5268"},{"range":"6282","text":"5270"},{"range":"6283","text":"5268"},{"range":"6284","text":"5270"},{"range":"6285","text":"5268"},{"range":"6286","text":"5270"},{"range":"6287","text":"5268"},{"range":"6288","text":"5270"},{"range":"6289","text":"5268"},{"range":"6290","text":"5270"},{"range":"6291","text":"5268"},{"range":"6292","text":"5270"},{"range":"6293","text":"5268"},{"range":"6294","text":"5270"},{"range":"6295","text":"5268"},{"range":"6296","text":"5270"},{"range":"6297","text":"5268"},{"range":"6298","text":"5270"},{"range":"6299","text":"5268"},{"range":"6300","text":"5270"},{"range":"6301","text":"5268"},{"range":"6302","text":"5270"},{"range":"6303","text":"5268"},{"range":"6304","text":"5270"},{"range":"6305","text":"5268"},{"range":"6306","text":"5270"},{"range":"6307","text":"5268"},{"range":"6308","text":"5270"},{"range":"6309","text":"5268"},{"range":"6310","text":"5270"},{"range":"6311","text":"5268"},{"range":"6312","text":"5270"},{"range":"6313","text":"5268"},{"range":"6314","text":"5270"},{"range":"6315","text":"5268"},{"range":"6316","text":"5270"},{"range":"6317","text":"5268"},{"range":"6318","text":"5270"},{"range":"6319","text":"5268"},{"range":"6320","text":"5270"},{"range":"6321","text":"5268"},{"range":"6322","text":"5270"},{"range":"6323","text":"5268"},{"range":"6324","text":"5270"},{"range":"6325","text":"5268"},{"range":"6326","text":"5270"},{"range":"6327","text":"5268"},{"range":"6328","text":"5270"},{"range":"6329","text":"5268"},{"range":"6330","text":"5270"},{"range":"6331","text":"5268"},{"range":"6332","text":"5270"},{"range":"6333","text":"5268"},{"range":"6334","text":"5270"},{"range":"6335","text":"5268"},{"range":"6336","text":"5270"},{"range":"6337","text":"5268"},{"range":"6338","text":"5270"},{"range":"6339","text":"5268"},{"range":"6340","text":"5270"},{"range":"6341","text":"5268"},{"range":"6342","text":"5270"},{"range":"6343","text":"5268"},{"range":"6344","text":"5270"},{"range":"6345","text":"5268"},{"range":"6346","text":"5270"},{"range":"6347","text":"5268"},{"range":"6348","text":"5270"},{"range":"6349","text":"5268"},{"range":"6350","text":"5270"},{"range":"6351","text":"5268"},{"range":"6352","text":"5270"},{"range":"6353","text":"5268"},{"range":"6354","text":"5270"},{"range":"6355","text":"5268"},{"range":"6356","text":"5270"},{"range":"6357","text":"5268"},{"range":"6358","text":"5270"},{"range":"6359","text":"5268"},{"range":"6360","text":"5270"},{"range":"6361","text":"5268"},{"range":"6362","text":"5270"},{"range":"6363","text":"5268"},{"range":"6364","text":"5270"},{"range":"6365","text":"5268"},{"range":"6366","text":"5270"},{"range":"6367","text":"5268"},{"range":"6368","text":"5270"},{"range":"6369","text":"5268"},{"range":"6370","text":"5270"},{"range":"6371","text":"5268"},{"range":"6372","text":"5270"},{"range":"6373","text":"5268"},{"range":"6374","text":"5270"},{"range":"6375","text":"5268"},{"range":"6376","text":"5270"},{"range":"6377","text":"5268"},{"range":"6378","text":"5270"},{"range":"6379","text":"5268"},{"range":"6380","text":"5270"},{"range":"6381","text":"5268"},{"range":"6382","text":"5270"},{"range":"6383","text":"5268"},{"range":"6384","text":"5270"},{"range":"6385","text":"5268"},{"range":"6386","text":"5270"},{"range":"6387","text":"5268"},{"range":"6388","text":"5270"},{"range":"6389","text":"5268"},{"range":"6390","text":"5270"},{"range":"6391","text":"5268"},{"range":"6392","text":"5270"},{"range":"6393","text":"5268"},{"range":"6394","text":"5270"},{"range":"6395","text":"5268"},{"range":"6396","text":"5270"},{"range":"6397","text":"5268"},{"range":"6398","text":"5270"},{"range":"6399","text":"5268"},{"range":"6400","text":"5270"},{"range":"6401","text":"5268"},{"range":"6402","text":"5270"},{"range":"6403","text":"5268"},{"range":"6404","text":"5270"},{"range":"6405","text":"5268"},{"range":"6406","text":"5270"},{"range":"6407","text":"5268"},{"range":"6408","text":"5270"},{"range":"6409","text":"5268"},{"range":"6410","text":"5270"},{"range":"6411","text":"5268"},{"range":"6412","text":"5270"},{"range":"6413","text":"5268"},{"range":"6414","text":"5270"},{"range":"6415","text":"5268"},{"range":"6416","text":"5270"},{"range":"6417","text":"5268"},{"range":"6418","text":"5270"},{"range":"6419","text":"5268"},{"range":"6420","text":"5270"},{"range":"6421","text":"5268"},{"range":"6422","text":"5270"},{"range":"6423","text":"5268"},{"range":"6424","text":"5270"},{"range":"6425","text":"5268"},{"range":"6426","text":"5270"},{"range":"6427","text":"5268"},{"range":"6428","text":"5270"},{"range":"6429","text":"5268"},{"range":"6430","text":"5270"},{"range":"6431","text":"5268"},{"range":"6432","text":"5270"},{"range":"6433","text":"5268"},{"range":"6434","text":"5270"},{"range":"6435","text":"5268"},{"range":"6436","text":"5270"},{"range":"6437","text":"5268"},{"range":"6438","text":"5270"},{"range":"6439","text":"5268"},{"range":"6440","text":"5270"},{"range":"6441","text":"5268"},{"range":"6442","text":"5270"},{"range":"6443","text":"5268"},{"range":"6444","text":"5270"},{"range":"6445","text":"5268"},{"range":"6446","text":"5270"},{"range":"6447","text":"5268"},{"range":"6448","text":"5270"},{"range":"6449","text":"5268"},{"range":"6450","text":"5270"},{"range":"6451","text":"5268"},{"range":"6452","text":"5270"},{"range":"6453","text":"5268"},{"range":"6454","text":"5270"},{"range":"6455","text":"5268"},{"range":"6456","text":"5270"},{"range":"6457","text":"5268"},{"range":"6458","text":"5270"},{"range":"6459","text":"5268"},{"range":"6460","text":"5270"},{"range":"6461","text":"5268"},{"range":"6462","text":"5270"},{"range":"6463","text":"5268"},{"range":"6464","text":"5270"},{"range":"6465","text":"5268"},{"range":"6466","text":"5270"},{"range":"6467","text":"5268"},{"range":"6468","text":"5270"},{"range":"6469","text":"5268"},{"range":"6470","text":"5270"},{"range":"6471","text":"5268"},{"range":"6472","text":"5270"},{"range":"6473","text":"5268"},{"range":"6474","text":"5270"},{"range":"6475","text":"5268"},{"range":"6476","text":"5270"},{"range":"6477","text":"5268"},{"range":"6478","text":"5270"},{"range":"6479","text":"5268"},{"range":"6480","text":"5270"},{"range":"6481","text":"5268"},{"range":"6482","text":"5270"},{"range":"6483","text":"5268"},{"range":"6484","text":"5270"},{"range":"6485","text":"5268"},{"range":"6486","text":"5270"},{"range":"6487","text":"5268"},{"range":"6488","text":"5270"},{"range":"6489","text":"5268"},{"range":"6490","text":"5270"},{"range":"6491","text":"5268"},{"range":"6492","text":"5270"},{"range":"6493","text":"5268"},{"range":"6494","text":"5270"},{"range":"6495","text":"5268"},{"range":"6496","text":"5270"},{"range":"6497","text":"5268"},{"range":"6498","text":"5270"},{"range":"6499","text":"5268"},{"range":"6500","text":"5270"},{"range":"6501","text":"5268"},{"range":"6502","text":"5270"},{"range":"6503","text":"5268"},{"range":"6504","text":"5270"},{"range":"6505","text":"5268"},{"range":"6506","text":"5270"},{"range":"6507","text":"5268"},{"range":"6508","text":"5270"},{"range":"6509","text":"5268"},{"range":"6510","text":"5270"},{"range":"6511","text":"5268"},{"range":"6512","text":"5270"},{"range":"6513","text":"5268"},{"range":"6514","text":"5270"},{"range":"6515","text":"5268"},{"range":"6516","text":"5270"},{"range":"6517","text":"5268"},{"range":"6518","text":"5270"},{"range":"6519","text":"5268"},{"range":"6520","text":"5270"},{"range":"6521","text":"5268"},{"range":"6522","text":"5270"},{"range":"6523","text":"5268"},{"range":"6524","text":"5270"},{"range":"6525","text":"5268"},{"range":"6526","text":"5270"},{"range":"6527","text":"5268"},{"range":"6528","text":"5270"},{"range":"6529","text":"5268"},{"range":"6530","text":"5270"},{"range":"6531","text":"5268"},{"range":"6532","text":"5270"},{"range":"6533","text":"5268"},{"range":"6534","text":"5270"},{"range":"6535","text":"5268"},{"range":"6536","text":"5270"},{"range":"6537","text":"5268"},{"range":"6538","text":"5270"},{"range":"6539","text":"5268"},{"range":"6540","text":"5270"},{"range":"6541","text":"5268"},{"range":"6542","text":"5270"},{"range":"6543","text":"5268"},{"range":"6544","text":"5270"},{"range":"6545","text":"5268"},{"range":"6546","text":"5270"},{"range":"6547","text":"5268"},{"range":"6548","text":"5270"},{"range":"6549","text":"5268"},{"range":"6550","text":"5270"},{"range":"6551","text":"5268"},{"range":"6552","text":"5270"},{"range":"6553","text":"5268"},{"range":"6554","text":"5270"},{"range":"6555","text":"5268"},{"range":"6556","text":"5270"},{"range":"6557","text":"5268"},{"range":"6558","text":"5270"},{"range":"6559","text":"5268"},{"range":"6560","text":"5270"},{"range":"6561","text":"5268"},{"range":"6562","text":"5270"},{"range":"6563","text":"5268"},{"range":"6564","text":"5270"},{"range":"6565","text":"5268"},{"range":"6566","text":"5270"},{"range":"6567","text":"5268"},{"range":"6568","text":"5270"},{"range":"6569","text":"5268"},{"range":"6570","text":"5270"},{"range":"6571","text":"5268"},{"range":"6572","text":"5270"},{"range":"6573","text":"5268"},{"range":"6574","text":"5270"},{"range":"6575","text":"5268"},{"range":"6576","text":"5270"},{"range":"6577","text":"5268"},{"range":"6578","text":"5270"},{"range":"6579","text":"5268"},{"range":"6580","text":"5270"},{"range":"6581","text":"5268"},{"range":"6582","text":"5270"},{"range":"6583","text":"5268"},{"range":"6584","text":"5270"},{"range":"6585","text":"5268"},{"range":"6586","text":"5270"},{"range":"6587","text":"5268"},{"range":"6588","text":"5270"},{"range":"6589","text":"5268"},{"range":"6590","text":"5270"},{"range":"6591","text":"5268"},{"range":"6592","text":"5270"},{"range":"6593","text":"5268"},{"range":"6594","text":"5270"},{"range":"6595","text":"5268"},{"range":"6596","text":"5270"},{"range":"6597","text":"5268"},{"range":"6598","text":"5270"},{"range":"6599","text":"5268"},{"range":"6600","text":"5270"},{"range":"6601","text":"5268"},{"range":"6602","text":"5270"},{"range":"6603","text":"5268"},{"range":"6604","text":"5270"},{"range":"6605","text":"5268"},{"range":"6606","text":"5270"},{"range":"6607","text":"5268"},{"range":"6608","text":"5270"},{"range":"6609","text":"5268"},{"range":"6610","text":"5270"},{"range":"6611","text":"5268"},{"range":"6612","text":"5270"},"removeEscape",{"range":"6613","text":"4794"},"Remove the `\\`. This maintains the current functionality.","escapeBackslash",{"range":"6614","text":"6615"},"Replace the `\\` with `\\\\` to include the actual backslash character.",{"range":"6616","text":"4794"},{"range":"6617","text":"6615"},{"range":"6618","text":"5268"},{"range":"6619","text":"5270"},{"range":"6620","text":"5268"},{"range":"6621","text":"5270"},[416,419],"unknown",[416,419],"never",[119,122],[119,122],[192,195],[192,195],[190,193],[190,193],[205,208],[205,208],[224,227],[224,227],[281,284],[281,284],[774,777],[774,777],[782,785],[782,785],[800,803],[800,803],[822,825],[822,825],[888,891],[888,891],[1279,1282],[1279,1282],[1320,1323],[1320,1323],[1422,1425],[1422,1425],[1865,1868],[1865,1868],[1906,1909],[1906,1909],[2019,2022],[2019,2022],[282,285],[282,285],[423,426],[423,426],[594,597],[594,597],[2969,2972],[2969,2972],[173,176],[173,176],[48968,48971],[48968,48971],[56785,56788],[56785,56788],[61306,61309],[61306,61309],[68047,68050],[68047,68050],[70193,70196],[70193,70196],[72224,72227],[72224,72227],[74253,74256],[74253,74256],[76726,76729],[76726,76729],[79294,79297],[79294,79297],[81747,81750],[81747,81750],[84222,84225],[84222,84225],[102629,102632],[102629,102632],[106160,106163],[106160,106163],[106905,106908],[106905,106908],[107672,107675],[107672,107675],[109622,109625],[109622,109625],[113500,113503],[113500,113503],[113911,113914],[113911,113914],[113941,113944],[113941,113944],[116118,116121],[116118,116121],[116152,116155],[116152,116155],[120440,120443],[120440,120443],[120474,120477],[120474,120477],[121005,121008],[121005,121008],[125920,125923],[125920,125923],[126008,126011],[126008,126011],[130708,130711],[130708,130711],[213,216],[213,216],[230,233],[230,233],[240,243],[240,243],[257,260],[257,260],[368,371],[368,371],[1885,1888],[1885,1888],[1242,1245],[1242,1245],[1923,1926],[1923,1926],[3199,3202],[3199,3202],[683,686],[683,686],[1344,1347],[1344,1347],[2011,2014],[2011,2014],[3357,3360],[3357,3360],[559,562],[559,562],[646,649],[646,649],[752,755],[752,755],[850,853],[850,853],[954,957],[954,957],[1059,1062],[1059,1062],[1171,1174],[1171,1174],[1286,1289],[1286,1289],[1390,1393],[1390,1393],[1501,1504],[1501,1504],[1602,1605],[1602,1605],[1748,1751],[1748,1751],[2343,2346],[2343,2346],[2563,2566],[2563,2566],[2575,2578],[2575,2578],[4918,4921],[4918,4921],[5548,5551],[5548,5551],[6990,6993],[6990,6993],[7276,7279],[7276,7279],[7698,7701],[7698,7701],[8193,8196],[8193,8196],[8837,8840],[8837,8840],[10045,10048],[10045,10048],[10227,10230],[10227,10230],[213,216],[213,216],[230,233],[230,233],[556,559],[556,559],[3097,3100],[3097,3100],[3102,3105],[3102,3105],[253,256],[253,256],[779,782],[779,782],[1700,1703],[1700,1703],[856,859],[856,859],[4385,4388],[4385,4388],[207,210],[207,210],[3447,3450],[3447,3450],[480,483],[480,483],[663,666],[663,666],[911,914],[911,914],[1160,1163],[1160,1163],[1522,1525],[1522,1525],[1885,1888],[1885,1888],[3308,3311],[3308,3311],[6041,6044],[6041,6044],[9545,9548],[9545,9548],[9709,9712],[9709,9712],[11109,11112],[11109,11112],[1484,1487],[1484,1487],[225,228],[225,228],[356,359],[356,359],[885,888],[885,888],[225,228],[225,228],[287,290],[287,290],[532,535],[532,535],[547,550],[547,550],[2184,2187],[2184,2187],[2200,2203],[2200,2203],[328,331],[328,331],[233,236],[233,236],[392,395],[392,395],[265,268],[265,268],[964,967],[964,967],[2612,2615],[2612,2615],[243,246],[243,246],[393,396],[393,396],[233,236],[233,236],[391,394],[391,394],[271,274],[271,274],[328,331],[328,331],[233,236],[233,236],[265,268],[265,268],[964,967],[964,967],[2643,2646],[2643,2646],[243,246],[243,246],[393,396],[393,396],[244,247],[244,247],[237,240],[237,240],[1108,1111],[1108,1111],[262,265],[262,265],[266,269],[266,269],[398,401],[398,401],[517,520],[517,520],[638,641],[638,641],[1066,1069],[1066,1069],[1199,1202],[1199,1202],[237,240],[237,240],[287,290],[287,290],[492,495],[492,495],[283,286],[283,286],[565,568],[565,568],[1689,1692],[1689,1692],[2572,2575],[2572,2575],[1220,1223],[1220,1223],[210,213],[210,213],[374,377],[374,377],[651,654],[651,654],[1775,1778],[1775,1778],[2599,2602],[2599,2602],[2648,2651],[2648,2651],[2803,2806],[2803,2806],[2843,2846],[2843,2846],[2885,2888],[2885,2888],[2898,2901],[2898,2901],[275,278],[275,278],[1967,1970],[1967,1970],[600,603],[600,603],[983,986],[983,986],[1377,1380],[1377,1380],[1400,1403],[1400,1403],[1592,1595],[1592,1595],[2339,2342],[2339,2342],[3161,3164],[3161,3164],[3358,3361],[3358,3361],[457,460],[457,460],[2795,2798],[2795,2798],[3196,3199],[3196,3199],[3297,3300],[3297,3300],[3411,3414],[3411,3414],[3509,3512],[3509,3512],[3703,3706],[3703,3706],[6527,6530],[6527,6530],[7987,7990],[7987,7990],[8390,8393],[8390,8393],[8582,8585],[8582,8585],[8650,8653],[8650,8653],[8834,8837],[8834,8837],[12127,12130],[12127,12130],[12285,12288],[12285,12288],[12361,12364],[12361,12364],[12877,12880],[12877,12880],[12962,12965],[12962,12965],[13097,13100],[13097,13100],[13625,13628],[13625,13628],[13637,13640],[13637,13640],[13781,13784],[13781,13784],[13846,13849],[13846,13849],[14338,14341],[14338,14341],[14350,14353],[14350,14353],[14445,14448],[14445,14448],[14511,14514],[14511,14514],[14532,14535],[14532,14535],[14554,14557],[14554,14557],[14593,14596],[14593,14596],[15274,15277],[15274,15277],[15286,15289],[15286,15289],[15430,15433],[15430,15433],[15597,15600],[15597,15600],[15687,15690],[15687,15690],[17058,17061],[17058,17061],[17070,17073],[17070,17073],[17571,17574],[17571,17574],[17583,17586],[17583,17586],[18406,18409],[18406,18409],[18418,18421],[18418,18421],[18756,18759],[18756,18759],[19171,19174],[19171,19174],[19183,19186],[19183,19186],[19287,19290],[19287,19290],[19760,19763],[19760,19763],[20670,20673],[20670,20673],[20682,20685],[20682,20685],[20917,20920],[20917,20920],[21310,21313],[21310,21313],[21771,21774],[21771,21774],[21783,21786],[21783,21786],[21851,21854],[21851,21854],[22491,22494],[22491,22494],[22769,22772],[22769,22772],[24350,24353],[24350,24353],[24362,24365],[24362,24365],[24752,24755],[24752,24755],[25225,25228],[25225,25228],[25237,25240],[25237,25240],[25768,25771],[25768,25771],[25780,25783],[25780,25783],[25853,25856],[25853,25856],[27009,27012],[27009,27012],[27021,27024],[27021,27024],[27345,27348],[27345,27348],[28034,28037],[28034,28037],[28046,28049],[28046,28049],[28549,28552],[28549,28552],[28561,28564],[28561,28564],[29734,29737],[29734,29737],[29746,29749],[29746,29749],[30174,30177],[30174,30177],[30664,30667],[30664,30667],[30676,30679],[30676,30679],[32310,32313],[32310,32313],[32834,32837],[32834,32837],[33087,33090],[33087,33090],[34019,34022],[34019,34022],[34475,34478],[34475,34478],[34490,34493],[34490,34493],[34972,34975],[34972,34975],[35004,35007],[35004,35007],[36012,36015],[36012,36015],[36192,36195],[36192,36195],[36755,36758],[36755,36758],[37393,37396],[37393,37396],[37405,37408],[37405,37408],[37423,37426],[37423,37426],[37765,37768],[37765,37768],[37977,37980],[37977,37980],[38111,38114],[38111,38114],[39584,39587],[39584,39587],[41655,41658],[41655,41658],[42013,42016],[42013,42016],[42033,42036],[42033,42036],[42101,42104],[42101,42104],[42429,42432],[42429,42432],[42482,42485],[42482,42485],[42498,42501],[42498,42501],[42514,42517],[42514,42517],[42654,42657],[42654,42657],[42924,42927],[42924,42927],[42936,42939],[42936,42939],[42948,42951],[42948,42951],[43182,43185],[43182,43185],[44891,44894],[44891,44894],[44963,44966],[44963,44966],[44979,44982],[44979,44982],[45689,45692],[45689,45692],[47319,47322],[47319,47322],[47331,47334],[47331,47334],[47345,47348],[47345,47348],[47357,47360],[47357,47360],[48599,48602],[48599,48602],[48646,48649],[48646,48649],[48724,48727],[48724,48727],[49333,49336],[49333,49336],[50330,50333],[50330,50333],[51881,51884],[51881,51884],[52211,52214],[52211,52214],[52270,52273],[52270,52273],[52353,52356],[52353,52356],[52532,52535],[52532,52535],[52584,52587],[52584,52587],[52594,52597],[52594,52597],[52816,52819],[52816,52819],[53083,53086],[53083,53086],[54995,54998],[54995,54998],[55011,55014],[55011,55014],[55671,55674],[55671,55674],[56104,56107],[56104,56107],[56637,56640],[56637,56640],[57529,57532],[57529,57532],[57906,57909],[57906,57909],[57917,57920],[57917,57920],[58518,58521],[58518,58521],[58802,58805],[58802,58805],[59236,59239],[59236,59239],[59551,59554],[59551,59554],[63803,63806],[63803,63806],[64193,64196],[64193,64196],[64694,64697],[64694,64697],[64708,64711],[64708,64711],[65590,65593],[65590,65593],[66086,66089],[66086,66089],[66100,66103],[66100,66103],[66559,66562],[66559,66562],[66750,66753],[66750,66753],[67484,67487],[67484,67487],[68628,68631],[68628,68631],[70687,70690],[70687,70690],[72675,72678],[72675,72678],[73351,73354],[73351,73354],[73602,73605],[73602,73605],[73808,73811],[73808,73811],[74131,74134],[74131,74134],[74654,74657],[74654,74657],[76831,76834],[76831,76834],[77144,77147],[77144,77147],[77236,77239],[77236,77239],[77550,77553],[77550,77553],[77581,77584],[77581,77584],[80529,80532],[80529,80532],[80644,80647],[80644,80647],[80687,80690],[80687,80690],[80737,80740],[80737,80740],[259,262],[259,262],[456,459],[456,459],[1167,1170],[1167,1170],[2633,2636],[2633,2636],[2647,2650],[2647,2650],[2746,2749],[2746,2749],[2925,2928],[2925,2928],[2939,2942],[2939,2942],[2979,2982],[2979,2982],[2985,2988],[2985,2988],[3149,3152],[3149,3152],[3568,3571],[3568,3571],[3580,3583],[3580,3583],[3594,3597],[3594,3597],[3675,3678],[3675,3678],[588,591],[588,591],[926,929],[926,929],[941,944],[941,944],[1198,1201],[1198,1201],[1428,1431],[1428,1431],[1827,1830],[1827,1830],[12962,12965],[12962,12965],[14349,14352],[14349,14352],[15739,15742],[15739,15742],[17515,17518],[17515,17518],[18411,18414],[18411,18414],[19599,19602],[19599,19602],[21147,21150],[21147,21150],[21160,21163],[21160,21163],[21171,21174],[21171,21174],[21196,21199],[21196,21199],[21610,21613],[21610,21613],[22207,22210],[22207,22210],[22667,22670],[22667,22670],[23140,23143],[23140,23143],[23158,23161],[23158,23161],[23445,23448],[23445,23448],[24029,24032],[24029,24032],[27536,27539],[27536,27539],[27546,27549],[27546,27549],[27559,27562],[27559,27562],[27922,27925],[27922,27925],[28388,28391],[28388,28391],[28867,28870],[28867,28870],[28885,28888],[28885,28888],[29172,29175],[29172,29175],[29452,29455],[29452,29455],[29481,29484],[29481,29484],[30198,30201],[30198,30201],[31185,31188],[31185,31188],[31212,31215],[31212,31215],[31236,31239],[31236,31239],[31296,31299],[31296,31299],[31333,31336],[31333,31336],[31352,31355],[31352,31355],[31377,31380],[31377,31380],[32008,32011],[32008,32011],[32791,32794],[32791,32794],[32802,32805],[32802,32805],[34079,34082],[34079,34082],[34458,34461],[34458,34461],[34469,34472],[34469,34472],[35304,35307],[35304,35307],[35496,35499],[35496,35499],[36829,36832],[36829,36832],[37101,37104],[37101,37104],[37112,37115],[37112,37115],[38206,38209],[38206,38209],[39293,39296],[39293,39296],[40424,40427],[40424,40427],[40687,40690],[40687,40690],[40698,40701],[40698,40701],[43024,43027],[43024,43027],[43287,43290],[43287,43290],[43298,43301],[43298,43301],[44121,44124],[44121,44124],[45190,45193],[45190,45193],[46381,46384],[46381,46384],[46655,46658],[46655,46658],[46666,46669],[46666,46669],[47337,47340],[47337,47340],[47635,47638],[47635,47638],[47646,47649],[47646,47649],[48608,48611],[48608,48611],[49820,49823],[49820,49823],[50783,50786],[50783,50786],[51098,51101],[51098,51101],[51109,51112],[51109,51112],[51805,51808],[51805,51808],[52120,52123],[52120,52123],[52131,52134],[52131,52134],[52815,52818],[52815,52818],[53561,53564],[53561,53564],[54267,54270],[54267,54270],[54893,54896],[54893,54896],[55924,55927],[55924,55927],[72084,72087],[72084,72087],[74283,74286],[74283,74286],[74987,74990],[74987,74990],[305,308],[305,308],[1124,1127],[1124,1127],[398,401],[398,401],[1364,1367],[1364,1367],[1964,1967],[1964,1967],[2402,2405],[2402,2405],[9755,9758],[9755,9758],[364,367],[364,367],[422,425],[422,425],[501,504],[501,504],[510,513],[510,513],[580,583],[580,583],[381,384],[381,384],[412,415],[412,415],[689,692],[689,692],[146,149],[146,149],[366,369],[366,369],[704,707],[704,707],[424,427],[424,427],[444,447],[444,447],[530,533],[530,533],[651,654],[651,654],[656,659],[656,659],[297,300],[297,300],[312,315],[312,315],[505,508],[505,508],[646,649],[646,649],[768,771],[768,771],[773,776],[773,776],[163,166],[163,166],[122,125],[122,125],[88,91],[88,91],[148,151],[148,151],[174,177],[174,177],[168,171],[168,171],[1178,1181],[1178,1181],[1183,1186],[1183,1186],[173,176],[173,176],[185,188],[185,188],[75,78],[75,78],[88,91],[88,91],[142,145],[142,145],[421,424],[421,424],[329,332],[329,332],[227,230],[227,230],[107,110],[107,110],[136,139],[136,139],[137,140],[137,140],[427,430],[427,430],[443,446],[443,446],[818,821],[818,821],[976,979],[976,979],[1292,1295],[1292,1295],[1321,1324],[1321,1324],[2578,2581],[2578,2581],[2589,2592],[2589,2592],[2780,2783],[2780,2783],[3104,3107],[3104,3107],[3119,3122],[3119,3122],[3138,3141],[3138,3141],[3195,3198],[3195,3198],[3246,3249],[3246,3249],[4670,4673],[4670,4673],[4685,4688],[4685,4688],[4703,4706],[4703,4706],[5264,5267],[5264,5267],[5337,5340],[5337,5340],[1673,1676],[1673,1676],[3071,3074],[3071,3074],[4218,4221],[4218,4221],[5998,6001],[5998,6001],[7681,7684],[7681,7684],[13502,13505],[13502,13505],[13960,13963],[13960,13963],[14461,14464],[14461,14464],[23715,23718],[23715,23718],[25405,25408],[25405,25408],[28150,28153],[28150,28153],[32559,32562],[32559,32562],[34410,34413],[34410,34413],[44130,44133],[44130,44133],[45797,45800],[45797,45800],[48519,48522],[48519,48522],[2187,2190],[2187,2190],[2555,2558],[2555,2558],[448,451],[448,451],[615,618],[615,618],[754,757],[754,757],[2090,2093],[2090,2093],[3176,3179],[3176,3179],[1247,1250],[1247,1250],[1260,1263],[1260,1263],[1275,1278],[1275,1278],[1281,1284],[1281,1284],[2171,2174],[2171,2174],[101,104],[101,104],[176,179],[176,179],[783,786],[783,786],[2022,2025],[2022,2025],[2204,2207],[2204,2207],[157,160],[157,160],[170,173],[170,173],[221,224],[221,224],[2047,2050],[2047,2050],[2683,2686],[2683,2686],[3514,3517],[3514,3517],[3910,3913],[3910,3913],[769,772],[769,772],[813,816],[813,816],[830,833],[830,833],[2169,2172],[2169,2172],[2805,2808],[2805,2808],[1275,1278],[1275,1278],[1334,1337],[1334,1337],[1869,1872],[1869,1872],[6083,6086],[6083,6086],[6805,6808],[6805,6808],[7503,7506],[7503,7506],[8342,8345],[8342,8345],[8348,8351],[8348,8351],[8507,8510],[8507,8510],[9325,9328],[9325,9328],[9461,9464],[9461,9464],[9745,9748],[9745,9748],[9757,9760],[9757,9760],[10086,10089],[10086,10089],[11555,11558],[11555,11558],[12298,12301],[12298,12301],[12317,12320],[12317,12320],[12437,12440],[12437,12440],[12849,12852],[12849,12852],[12953,12956],[12953,12956],[13509,13512],[13509,13512],[14978,14981],[14978,14981],[16216,16219],[16216,16219],[16260,16263],[16260,16263],[16800,16803],[16800,16803],[17018,17021],[17018,17021],[17082,17085],[17082,17085],[17643,17646],[17643,17646],[19853,19856],[19853,19856],[19864,19867],[19864,19867],[20710,20713],[20710,20713],[20724,20727],[20724,20727],[20747,20750],[20747,20750],[20793,20796],[20793,20796],[21050,21053],[21050,21053],[21324,21327],[21324,21327],[21335,21338],[21335,21338],[21826,21829],[21826,21829],[21837,21840],[21837,21840],[22189,22192],[22189,22192],[22200,22203],[22200,22203],[23310,23313],[23310,23313],[23320,23323],[23320,23323],[23331,23334],[23331,23334],[23340,23343],[23340,23343],[23484,23487],[23484,23487],[23496,23499],[23496,23499],[23832,23835],[23832,23835],[23844,23847],[23844,23847],[24183,24186],[24183,24186],[24195,24198],[24195,24198],[24310,24313],[24310,24313],[24322,24325],[24322,24325],[24902,24905],[24902,24905],[25016,25019],[25016,25019],[25130,25133],[25130,25133],[25243,25246],[25243,25246],[25356,25359],[25356,25359],[25471,25474],[25471,25474],[25585,25588],[25585,25588],[25702,25705],[25702,25705],[25822,25825],[25822,25825],[25937,25940],[25937,25940],[26760,26763],[26760,26763],[26908,26911],[26908,26911],[27233,27236],[27233,27236],[27268,27271],[27268,27271],[1224,1227],[1224,1227],[1415,1418],[1415,1418],[886,889],[886,889],[2646,2649],[2646,2649],[3348,3351],[3348,3351],[3535,3538],[3535,3538],[4306,4309],[4306,4309],[4894,4897],[4894,4897],[335,338],[335,338],[358,361],[358,361],[436,439],[436,439],[1299,1302],[1299,1302],[1315,1318],[1315,1318],[136,139],[136,139],[152,155],[152,155],[395,398],[395,398],[56,59],[56,59],[366,369],[366,369],[591,594],[591,594],[888,891],[888,891],[186,189],[186,189],[196,199],[196,199],[232,235],[232,235],[242,245],[242,245],[455,458],[455,458],[465,468],[465,468],[503,506],[503,506],[527,530],[527,530],[573,576],[573,576],[583,586],[583,586],[857,860],[857,860],[972,975],[972,975],[1078,1081],[1078,1081],[1095,1098],[1095,1098],[1288,1291],[1288,1291],[1305,1308],[1305,1308],[1322,1325],[1322,1325],[1339,1342],[1339,1342],[1357,1360],[1357,1360],[2213,2216],[2213,2216],[2816,2819],[2816,2819],[2827,2830],[2827,2830],[2841,2844],[2841,2844],[2856,2859],[2856,2859],[3147,3150],[3147,3150],[3159,3162],[3159,3162],[3172,3175],[3172,3175],[3194,3197],[3194,3197],[4104,4107],[4104,4107],[4115,4118],[4115,4118],[4244,4247],[4244,4247],[1828,1829],[1828,1828],"\\",[3334,3335],[3334,3334],[536,539],[536,539],[1182,1185],[1182,1185]] \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 42cce276..982867ff 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,7 +4,6 @@ about: Create a report to help us improve title: '' labels: '' assignees: '' - --- **Describe the bug** @@ -15,6 +14,7 @@ What release version or branch are you experiencing the behavior **To Reproduce** Steps to reproduce the behavior: + 1. Create form... 2. Add component... 3. Use form... diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7d..2f28cead 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -4,7 +4,6 @@ about: Suggest an idea for this project title: '' labels: '' assignees: '' - --- **Is your feature request related to a problem? Please describe.** diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 35ec1a47..1e393e0f 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -6,23 +6,23 @@ https://formio.atlassian.net/browse/FIO-XXXX **What changed?** -*Use this section to provide a summary description of the changes you've made* +_Use this section to provide a summary description of the changes you've made_ **Why have you chosen this solution?** -*Use this section to justify your choices* +_Use this section to justify your choices_ ## Breaking Changes / Backwards Compatibility -*Use this section to describe any potentially breaking changes this PR introduces or any effects this PR might have on backwards compatibility* +_Use this section to describe any potentially breaking changes this PR introduces or any effects this PR might have on backwards compatibility_ ## Dependencies -*Use this section to list any dependent changes/PRs in other Form.io modules* +_Use this section to list any dependent changes/PRs in other Form.io modules_ ## How has this PR been tested? -*Use this section to describe how you tested your changes; if you haven't included automated tests, justify your reasoning* +_Use this section to describe how you tested your changes; if you haven't included automated tests, justify your reasoning_ ## Checklist: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f2b0b447..35a36f8d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,7 +94,7 @@ jobs: run: | git fetch origin ${{ github.event.pull_request.base.ref }}:${{ github.event.pull_request.base.ref }} git merge ${{ github.event.pull_request.base.ref }} --no-commit --no-ff - + - name: Check for merge conflicts run: | if ! git merge --no-commit --no-ff ${{ github.event.pull_request.base.ref }}; then @@ -167,17 +167,17 @@ jobs: # Extract the pull request number and the short SHA of the commit PR_NUMBER=$(echo ${{ github.event.number }}) COMMIT_SHORT_SHA=$(echo "${{ github.event.pull_request.head.sha }}" | cut -c1-7) - + # Extract the current version from package.json CURRENT_VERSION=$(node -p "require('./package.json').version") - + # If the current version includes '-rc.', remove it and everything after # This step ensures that we start with a base version like '3.0.0' even if it was a release candidate BASE_VERSION=$(echo "$CURRENT_VERSION" | cut -d'-' -f1) - + # Construct the new version string NEW_VERSION="${BASE_VERSION}-dev.${PR_NUMBER}.${COMMIT_SHORT_SHA}" - + # Output the new version for use in subsequent GitHub Actions steps echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV @@ -188,4 +188,4 @@ jobs: - name: Publish to npm run: | npm version $NEW_VERSION - yarn publish --tag dev \ No newline at end of file + yarn publish --tag dev diff --git a/.husky/.gitignore b/.husky/.gitignore new file mode 100644 index 00000000..31354ec1 --- /dev/null +++ b/.husky/.gitignore @@ -0,0 +1 @@ +_ diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000..36af2198 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx lint-staged diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..f5664018 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,11 @@ +/node_modules/ +/dist/ +/build/ +/lib/ +/artifacts/ +/coverage/ +/docs/ +.git/ +.nyc_output/ +.vscode/ +yarn.lock diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..554f2a3b --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "printWidth": 100 +} diff --git a/Changelog.md b/Changelog.md index 3ddf2628..377ef3c0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,282 +1,364 @@ ## [Unreleased: 2.3.1-rc.1] + ### Changed - - Regression | Nested Form | Components in Nested forms should not validate hidden components without Validate When Hidden = true - - FIO-8807: fixed an issue where conditionals based on selectBoxes component do not work - - FIO-8778: add case for map component model type in filter; add tests - - FIO-8347: Added ability to skip mask validation - - FIO-8731: Update fix to nested hidden components - - FIO-8731: Fixes component gets validated when being in a hidden parent - - FIO-8273 fixed advanced logic for data components - - FIO-8730: Fix submission has hidden fields when 'Clear value when hidden' is checked - - FIO-8626: Updated conditionally hidden logic - - FIO-7733: update most form params to optional - - fixing child components being displayed when they should be removed when clearOnHide is set - - FIO-8639 fixed validation for select component if onlyAvailableItems is set to false - - FIO-8645: added tests and translations for validateRequiredDay - - FIO-8537: Fixing the filter processor to handle nested component data properly - - FIO-8597: fixed an issue with an empty array value for a number component with multiple values enabled - - FIO-8798: updated day component validation - - FIO-8885 & FIO-8886: use strict equality check for conditional component paths rather than Array.prototype.includes - - FIO-8810: fixed an issue where user unables to resubmit (change) the form with several levels of nested forms with required fields - - FIO-8848 fixed validation for TextArea with Save as Json - - FIO-8769: added check for the simpleConditional properties state - - FIO-8901: fixed incorrect handling of excessive rows in nested array model - - FIO-8912: update validateMultiple to account for model types - - fix formiojs tests - - FIO-8798: update normalization for day component - - FIO-8986 fixed validation for Day component with two hidden fields - - FIO-8912: updates to model types, naming - - FIO-8414: fixed required validation not working in Data Grid - - FIO-8986: fixed normalization for day with default value and hidden fields - - FIO-9059: fixed an issue where the string type returns for textarea with json type - - FIO-9033 tagpad data is not saved - - FIO-9028: update README - - FIO-9085: Fix components data removed from submission when conditional set for Address component value - - FIO-9055: separate rowPath from componentPath in getComponentActualValue fn - - FIO-8723: Clear values from submission for hidden comp with clearOnHide flag - - FIO-9143 fixed getValidationFormat error - - FIO-9002: fix issue with conditionally hidden duplicate nested form paths - - FIO-9085: Fix address submission logic - - FIO-8954: added Allow only available values validation for Data Source Type = URL + +- Regression | Nested Form | Components in Nested forms should not validate hidden components without Validate When Hidden = true +- FIO-8807: fixed an issue where conditionals based on selectBoxes component do not work +- FIO-8778: add case for map component model type in filter; add tests +- FIO-8347: Added ability to skip mask validation +- FIO-8731: Update fix to nested hidden components +- FIO-8731: Fixes component gets validated when being in a hidden parent +- FIO-8273 fixed advanced logic for data components +- FIO-8730: Fix submission has hidden fields when 'Clear value when hidden' is checked +- FIO-8626: Updated conditionally hidden logic +- FIO-7733: update most form params to optional +- fixing child components being displayed when they should be removed when clearOnHide is set +- FIO-8639 fixed validation for select component if onlyAvailableItems is set to false +- FIO-8645: added tests and translations for validateRequiredDay +- FIO-8537: Fixing the filter processor to handle nested component data properly +- FIO-8597: fixed an issue with an empty array value for a number component with multiple values enabled +- FIO-8798: updated day component validation +- FIO-8885 & FIO-8886: use strict equality check for conditional component paths rather than Array.prototype.includes +- FIO-8810: fixed an issue where user unables to resubmit (change) the form with several levels of nested forms with required fields +- FIO-8848 fixed validation for TextArea with Save as Json +- FIO-8769: added check for the simpleConditional properties state +- FIO-8901: fixed incorrect handling of excessive rows in nested array model +- FIO-8912: update validateMultiple to account for model types +- fix formiojs tests +- FIO-8798: update normalization for day component +- FIO-8986 fixed validation for Day component with two hidden fields +- FIO-8912: updates to model types, naming +- FIO-8414: fixed required validation not working in Data Grid +- FIO-8986: fixed normalization for day with default value and hidden fields +- FIO-9059: fixed an issue where the string type returns for textarea with json type +- FIO-9033 tagpad data is not saved +- FIO-9028: update README +- FIO-9085: Fix components data removed from submission when conditional set for Address component value +- FIO-9055: separate rowPath from componentPath in getComponentActualValue fn +- FIO-8723: Clear values from submission for hidden comp with clearOnHide flag +- FIO-9143 fixed getValidationFormat error +- FIO-9002: fix issue with conditionally hidden duplicate nested form paths +- FIO-9085: Fix address submission logic +- FIO-8954: added Allow only available values validation for Data Source Type = URL ## 2.3.0-rc.1 + ### Changed - - updated thresholds to current values - - FIO-8450: Fix custom error message for unique validation - - FIO-8598 fixed normalization of radio component values depending on storage type - - FIO-8650 -- returning empty array for empty edit grids - - FIO-8477: Fix the timezones issue in formatDate function - + +- updated thresholds to current values +- FIO-8450: Fix custom error message for unique validation +- FIO-8598 fixed normalization of radio component values depending on storage type +- FIO-8650 -- returning empty array for empty edit grids +- FIO-8477: Fix the timezones issue in formatDate function + ## 2.2.0-rc.1 + ### Changed - - FIO-8177: fix unsetting empty array values - - FIO-8185: Fixing issues with EditGrid and DataGrid clearOnHide with Conditionally visible elements - - FIO-8178: correctly add "validator" param to interpolated error object - - FIO-8121: Fix json and custom validation errors response - - FIO-8128: allow export of dist minified js - - FIO-8143: update eachComponent to be able to return proper pathing - - FIO-8210: fix nested form validation - - change filter processor to be more verbose and have compModelType in scope (replaces pull #78) - - FIO 7488: improve error handling - - Fixed required validation considering false value falsy (pull #31) - - Revert "Merge pull request #31 from ralfeis/master" - - FIO-8037: fixed an issue where number component can be sent text through API - - FIO-7964: add resource-based select component validation - - FIO-8218: Fix tests for PR 79 - - FIO-8218: add tests for FIO-8210 - - Fix/implement pattern message - - FIO-8128: adds includeAll flag to eachComponentData and eachComponentDataAsync - - FIO-7507: publish-dev-tag-to-npm - - FIO-8264: update validate required - - FIO-8336 fix validation on multiple values - - FIO-8037: added number component normalization - - FIO-8288: do not validate dates in textfield components with calendar widgets - - FIO-8254 fixed available values validation error for Select component - - FIO-8281: fixed sync validation error for select component with url data src - - update validate required recursion to not recurse when nested data type - - FIO-7675: remove Map Key From Core (cycled out) - - FIO-8027 added Cloudflare Turnstile as a captcha Provider - - Fixing the truncate multiple spaces so it does not mutate the data in the validation system - - FIO-8354: fallback to passing response in argument if response.body is undefined - - Changes to the Experimental Exports, and changes for 5.x Renderer - - Experimental component changes - - FIO-8597: fixed an issue with a blank value for a number component with multiple values enabled - - FIO-8512: fixed an issue where conditionally visible data inside layout components inside editGrid/dataGrid is unset on server side - - FIO-8316 invalid data submitted in nested form - - fix path/import issue with JSONLogicEvaluator +- FIO-8177: fix unsetting empty array values +- FIO-8185: Fixing issues with EditGrid and DataGrid clearOnHide with Conditionally visible elements +- FIO-8178: correctly add "validator" param to interpolated error object +- FIO-8121: Fix json and custom validation errors response +- FIO-8128: allow export of dist minified js +- FIO-8143: update eachComponent to be able to return proper pathing +- FIO-8210: fix nested form validation +- change filter processor to be more verbose and have compModelType in scope (replaces pull #78) +- FIO 7488: improve error handling +- Fixed required validation considering false value falsy (pull #31) +- Revert "Merge pull request #31 from ralfeis/master" +- FIO-8037: fixed an issue where number component can be sent text through API +- FIO-7964: add resource-based select component validation +- FIO-8218: Fix tests for PR 79 +- FIO-8218: add tests for FIO-8210 +- Fix/implement pattern message +- FIO-8128: adds includeAll flag to eachComponentData and eachComponentDataAsync +- FIO-7507: publish-dev-tag-to-npm +- FIO-8264: update validate required +- FIO-8336 fix validation on multiple values +- FIO-8037: added number component normalization +- FIO-8288: do not validate dates in textfield components with calendar widgets +- FIO-8254 fixed available values validation error for Select component +- FIO-8281: fixed sync validation error for select component with url data src +- update validate required recursion to not recurse when nested data type +- FIO-7675: remove Map Key From Core (cycled out) +- FIO-8027 added Cloudflare Turnstile as a captcha Provider +- Fixing the truncate multiple spaces so it does not mutate the data in the validation system +- FIO-8354: fallback to passing response in argument if response.body is undefined +- Changes to the Experimental Exports, and changes for 5.x Renderer +- Experimental component changes +- FIO-8597: fixed an issue with a blank value for a number component with multiple values enabled +- FIO-8512: fixed an issue where conditionally visible data inside layout components inside editGrid/dataGrid is unset on server side +- FIO-8316 invalid data submitted in nested form +- fix path/import issue with JSONLogicEvaluator ## 2.0.0-rc.24 + ### Changed - - FIO-8106: add default storeas value to tags - - FIO-8106: add invalidDate error translation + +- FIO-8106: add default storeas value to tags +- FIO-8106: add invalidDate error translation ## 2.0.0-rc.23 + ### Changed - - Fix: JSONLogic validations should get same context as calculations - + +- Fix: JSONLogic validations should get same context as calculations + ## 2.0.0-rc.22 + ### Changed - - FIO-7146: gh actions for repository - - FIO-8100: add clearhidden processor to cover logic, conditions, and custom - - FIO-8101: always process json validation even if value is falsy - - FIO-8107: correct small error in normalize processor - + +- FIO-7146: gh actions for repository +- FIO-8100: add clearhidden processor to cover logic, conditions, and custom +- FIO-8101: always process json validation even if value is falsy +- FIO-8107: correct small error in normalize processor + ## 2.0.0-rc.21 + ### Changed - - FIO-8092: update isEmpty to isComponentDataEmpty and account for differing component data types + +- FIO-8092: update isEmpty to isComponentDataEmpty and account for differing component data types ## 2.0.0-rc.20 + ### Changed - - FIO-8086: don't multiple validate select components - - FIO-8079: add stricter time validation - + +- FIO-8086: don't multiple validate select components +- FIO-8079: add stricter time validation + ## 2.0.0-rc.19 + ### Changed - - FIO-8047: add dereferencing processor for datatable comp - + +- FIO-8047: add dereferencing processor for datatable comp + ## 2.0.0-rc.18 + ### Changed - - FIO-8055: validate components that include custom validations, even when their data is empty - - FIO-8049: fix value prop in evaluations - - FIO-8040: add functions from formiojs - - restructure conditional processor to fix conditional components in emails + +- FIO-8055: validate components that include custom validations, even when their data is empty +- FIO-8049: fix value prop in evaluations +- FIO-8040: add functions from formiojs +- restructure conditional processor to fix conditional components in emails ## 2.0.0-rc.17 + ### Changed - - FIO-8023: Fixing issues with the parent traversal on deeply nested components within nested forms - + +- FIO-8023: Fixing issues with the parent traversal on deeply nested components within nested forms + ## 2.0.0-rc.16 - - FIO-7884: Fixed issues with processing data within nested form data structures + +- FIO-7884: Fixed issues with processing data within nested form data structures ## 2.0.0-rc.14 + ### Changed - - FIO-7884: Fixed an issue with nested form data where it would not set correctly - - FIO-7938: Fixing issues where components within Array components (like datagrid) would get the path of the first index assigned and would never update again - - FIO-7958: add asynchronous rule set - - FIO-7958: fix typo in normalize processor fn - - FIO-7998: add validate captcha rule - - FIO-7991: Fixing the time validation to use the dataFormat for validation, which is what the client passes along to the server - - skip processing if row is null or undefined + +- FIO-7884: Fixed an issue with nested form data where it would not set correctly +- FIO-7938: Fixing issues where components within Array components (like datagrid) would get the path of the first index assigned and would never update again +- FIO-7958: add asynchronous rule set +- FIO-7958: fix typo in normalize processor fn +- FIO-7998: add validate captcha rule +- FIO-7991: Fixing the time validation to use the dataFormat for validation, which is what the client passes along to the server +- skip processing if row is null or undefined ## 2.0.0-rc.13 - - FIO-7958: add normalize processor fn and derive context.value rather than mutate it directly - + +- FIO-7958: add normalize processor fn and derive context.value rather than mutate it directly + ## 2.0.0-rc.11 - - FIO-7883: include premium components in 'multiple' validation conditional - - FIO-7885: Make the core validator run the skipValidation checks similar to renderer checks - - fix calculation for nested forms - - FIO-7938: Fixing the fetch process to evaluate properly on the server - - FIO-7874: Fixed issues with 'Invalid Time' when submitting a time component - - FIO-7733: move unused 'experimental' features to a new folder and remove them f - - Processor changes to work with other forms and validation processes - - scopes updated and other little updates - - Adding processors for server-side data processing - - Ensure we do not 'append' jwt tokens but set them - + +- FIO-7883: include premium components in 'multiple' validation conditional +- FIO-7885: Make the core validator run the skipValidation checks similar to renderer checks +- fix calculation for nested forms +- FIO-7938: Fixing the fetch process to evaluate properly on the server +- FIO-7874: Fixed issues with 'Invalid Time' when submitting a time component +- FIO-7733: move unused 'experimental' features to a new folder and remove them f +- Processor changes to work with other forms and validation processes +- scopes updated and other little updates +- Adding processors for server-side data processing +- Ensure we do not 'append' jwt tokens but set them + ## 2.0.0-rc.10 + ### Breaking Changes - - This version of the renderer will now produce different "binary" build files. The following are created. - - dist/formio.core.js => The complete core binary. This used to be "dist/index.js". - - dist/formio.base.js => The base components of the core library. This used to be "dist/base/index.js" - - dist/formio.components.js => The extended components classes of the core library. This used to be "dist/components/index.js" - - dist/formio.model.js => This is the data model base classes for the renderer. This used to be "dist/model/index.js" - - dist/formio.modules.js => The different modules such as "jsonlogic" used when rendering. This used to be "dist/modules/index.js" - - dist/formio.js => The Formio SDK => this used to be "dist/sdk/index.js" - - dist/formio.utils.js => The Formio Utils library => this used to be "dist/utils/index.js" - - dist/formio.template.js => The template handling library => this used to be "dist/template/index.js" - - dist/formio.process.js => The processing engine, such as validation => this used to be "dist/process/index.js" - - - This version introduces the "processors" concept to our core library. This will become the "core" validation engine and data processing engine for - our renderer as well as server side logic. - - - This version introduces the "template" handling logic so that it can be used by other libraries to manage templates. + +- This version of the renderer will now produce different "binary" build files. The following are created. + + - dist/formio.core.js => The complete core binary. This used to be "dist/index.js". + - dist/formio.base.js => The base components of the core library. This used to be "dist/base/index.js" + - dist/formio.components.js => The extended components classes of the core library. This used to be "dist/components/index.js" + - dist/formio.model.js => This is the data model base classes for the renderer. This used to be "dist/model/index.js" + - dist/formio.modules.js => The different modules such as "jsonlogic" used when rendering. This used to be "dist/modules/index.js" + - dist/formio.js => The Formio SDK => this used to be "dist/sdk/index.js" + - dist/formio.utils.js => The Formio Utils library => this used to be "dist/utils/index.js" + - dist/formio.template.js => The template handling library => this used to be "dist/template/index.js" + - dist/formio.process.js => The processing engine, such as validation => this used to be "dist/process/index.js" + +- This version introduces the "processors" concept to our core library. This will become the "core" validation engine and data processing engine for + our renderer as well as server side logic. + +- This version introduces the "template" handling logic so that it can be used by other libraries to manage templates. ## 1.3.0-rc.22 + ### Fixed - - FIO-7462: fix failing tests + +- FIO-7462: fix failing tests ## 1.3.0-rc.20 + ### Changed - - Adding form and instance proxies + +- Adding form and instance proxies ## 1.3.0-rc.18 + ### Fixed - - revert accidental deletion of templateSettings + +- revert accidental deletion of templateSettings ## 1.3.0-rc.16 + ### Fixed - - Adding exports to libraries. + +- Adding exports to libraries. ## 1.3.0-rc.14 + ### Fixed - - Issue with invalid alias when loading a form with form revision. + +- Issue with invalid alias when loading a form with form revision. ## 1.3.0-rc.13 + ### Fixed - - FIO-6832: fixed issue where submission used wrong _fvid + +- FIO-6832: fixed issue where submission used wrong \_fvid ### Changed - - Upgrade all dependencies to latest versions. + +- Upgrade all dependencies to latest versions. ## 1.3.0-rc.9 - - Upgrade all dependencies to latest versions. + +- Upgrade all dependencies to latest versions. ## 1.3.0-rc.8 + ## 1.3.0-rc.7 + ### Fixed - - Fixed the ejs.js template import. + +- Fixed the ejs.js template import. ## 1.3.0-rc.6 + ### Changed - - Fixed the export lib to contain relative paths for easy import. + +- Fixed the export lib to contain relative paths for easy import. ## 1.3.0-rc.5 + ### Changed - - Fixing the lib to contain production build of js files. + +- Fixing the lib to contain production build of js files. ## 1.3.0-rc.4 + ### Changed - - "main" in package.json changed to "dist" to support imports into other libraries. + +- "main" in package.json changed to "dist" to support imports into other libraries. ## 1.3.0-rc.2 - 1.3.0-rc.3 + ### Changed - - Experiment with typescript paths and imports. + +- Experiment with typescript paths and imports. ## 1.3.0-rc.1 + ### Changed - - Added types for core formio entities - - Missing commits from formio.js implemented + +- Added types for core formio entities +- Missing commits from formio.js implemented ## 1.2.0 + ### Fixed - - FIO-6123: Added an array cleanup to the removeAttachedListeners method and wrote test for it + +- FIO-6123: Added an array cleanup to the removeAttachedListeners method and wrote test for it ## 1.1.0 + ### Changed - - FIO-5147: Added a check for an empty value + +- FIO-5147: Added a check for an empty value ## 1.0.0 + ### Changed - - Official Release + +- Official Release ## 1.0.0-rc.5 + ### Fixed - - FIO-3999: Fixed Data Table loading for IE11 + +- FIO-3999: Fixed Data Table loading for IE11 ## 1.0.0-rc.2 + ### Fixed - - FIO-599: Fixes no values on pdf download for components inside nested form - - FIO-2849: Fix: Evaluator does not interpolate expressions with optional chaining properly + +- FIO-599: Fixes no values on pdf download for components inside nested form +- FIO-2849: Fix: Evaluator does not interpolate expressions with optional chaining properly ## 0.0.8 + ### Changed - - Added override method. + +- Added override method. ## 0.0.7 + ### Changed - - Refactored array types. + +- Refactored array types. ## 0.0.6 + ### Changed - - Added a Components.render method. + +- Added a Components.render method. ## 0.0.5 + ### Changed - - How certain packages are imported. + +- How certain packages are imported. ## 0.0.4 + ### Chaanged - - Added unwind functionality and more functions to the utils. + +- Added unwind functionality and more functions to the utils. ## 0.0.3 + ### Changed - - Added some date conversion methods. + +- Added some date conversion methods. ## 0.0.2 + ### Changed - - Many refactorings and added data handling and basic inputs. + +- Many refactorings and added data handling and basic inputs. ## 0.0.1 + ### Changed - - Initial commit. + +- Initial commit. diff --git a/Readme.md b/Readme.md index b7720bf6..38aa71cd 100644 --- a/Readme.md +++ b/Readme.md @@ -31,54 +31,54 @@ To run a suite of processor functions on a form and a submission, the `process` import { processSync } from '@formio/core'; const form = { - display: 'form', - components: [ - { - type: 'textfield', - key: 'firstName', - label: 'First Name', - input: true, - }, - { - type: 'textfield', - key: 'lastName', - label: 'Last Name', - input: true, - }, - { - type: 'button', - key: 'submit', - action: 'submit', - label: 'Submit', - }, - ], + display: 'form', + components: [ + { + type: 'textfield', + key: 'firstName', + label: 'First Name', + input: true, + }, + { + type: 'textfield', + key: 'lastName', + label: 'Last Name', + input: true, + }, + { + type: 'button', + key: 'submit', + action: 'submit', + label: 'Submit', + }, + ], }; const submission = { - data: { - firstName: 'John', - lastName: 'Doe', - }, + data: { + firstName: 'John', + lastName: 'Doe', + }, }; const addExclamationSync = (context) => { - const { component, data, scope, path, value } = context; + const { component, data, scope, path, value } = context; - if (!scope.addExclamation) scope.addExclamation = {}; - let newValue = `${value}!`; + if (!scope.addExclamation) scope.addExclamation = {}; + let newValue = `${value}!`; - // The scope is a rolling "results" object that tracks which components have been operated on by which processor functions - scope.addExclamation[path] = true; - _.set(data, path, newValue); - return; + // The scope is a rolling "results" object that tracks which components have been operated on by which processor functions + scope.addExclamation[path] = true; + _.set(data, path, newValue); + return; }; // The context object is mutated depending on which component is being processed; after `processSync` it will contain the processed components and data const context = { - components: form.components, - data: submission.data, - processors: [{ processSync: addExclamationSync }], - scope: {}, + components: form.components, + data: submission.data, + processors: [{ processSync: addExclamationSync }], + scope: {}, }; // The `process` family of functions returns the scope object @@ -114,8 +114,8 @@ Next, you can create a new component as follows. ```js import { Components } from '@formio/core/experimental'; Components.addComponent({ - type: 'h3', - template: (ctx) => `

${ctx.component.header}

` + type: 'h3', + template: (ctx) => `

${ctx.component.header}

`, }); ``` @@ -123,10 +123,10 @@ And now this component will render using the following. ```js const header = Components.createComponent({ - type: 'h3', - header: 'This is a test', + type: 'h3', + header: 'This is a test', }); -console.log(header.render()); // Outputs

This is a test

+console.log(header.render()); // Outputs

This is a test

``` You can also use this library by including it in your webpage scripts by including the following. @@ -138,26 +138,31 @@ You can also use this library by including it in your webpage scripts by includi After you do this, you can then do the following to create a Data Table in your website. ```js -FormioCore.render(document.getElementById('data-table'), { +FormioCore.render( + document.getElementById('data-table'), + { type: 'datatable', key: 'customers', components: [ - { - type: 'datavalue', - key: 'firstName', - label: 'First Name' - }, - { - type: 'datavalue', - key: 'lastName', - label: 'First Name' - } - ] -}, {}, { + { + type: 'datavalue', + key: 'firstName', + label: 'First Name', + }, + { + type: 'datavalue', + key: 'lastName', + label: 'First Name', + }, + ], + }, + {}, + { customers: [ - {firstName: 'Joe', lastName: 'Smith'}, - {firstName: 'Sally', lastName: 'Thompson'}, - {firstName: 'Mary', lastName: 'Bono'} - ] -}); + { firstName: 'Joe', lastName: 'Smith' }, + { firstName: 'Sally', lastName: 'Thompson' }, + { firstName: 'Mary', lastName: 'Bono' }, + ], + }, +); ``` diff --git a/config/webpack.config.js b/config/webpack.config.js index b917746c..1e6a278f 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -8,40 +8,40 @@ module.exports = { 'formio.modules.js': './src/modules/index.ts', 'formio.js': './src/sdk/index.ts', 'formio.utils.js': './src/utils/index.ts', - 'formio.process.js': './src/process/index.ts' + 'formio.process.js': './src/process/index.ts', }, output: { library: { type: 'umd', - name: 'FormioCore' + name: 'FormioCore', }, path: path.resolve(__dirname, '../dist'), filename: '[name]', environment: { - arrowFunction: false + arrowFunction: false, }, }, plugins: [ new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/, - }) + }), ], resolve: { extensions: ['.ts', '.js'], plugins: [ new TsconfigPathsPlugin({ - configFile: path.resolve(__dirname, '..', 'tsconfig.json') - }) - ] + configFile: path.resolve(__dirname, '..', 'tsconfig.json'), + }), + ], }, module: { rules: [ { test: /\.ts$/, exclude: /\.spec\.ts$/, - loader: "ts-loader" - } - ] - } + loader: 'ts-loader', + }, + ], + }, }; diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..e717890a --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,42 @@ +import globals from 'globals'; +import pluginJs from '@eslint/js'; +import mochaPlugin from 'eslint-plugin-mocha'; +import tseslint from 'typescript-eslint'; + +export default [ + { + ignores: [ + 'dist/**/*', + 'lib/**/*', + 'coverage/**/*', + '.github/**/*', + 'node_modules/**/*', + 'docs/**/*', + 'config/**/*', + 'src/experimental/**/*', + 'src/server/**/*', + ], + }, + { files: ['**/*.{js,mjs,cjs,ts}'] }, + { + languageOptions: { globals: { ...globals.browser, ...globals.node } }, + }, + pluginJs.configs.recommended, + mochaPlugin.configs.flat.recommended, + ...tseslint.configs.recommended, + { + rules: { + 'no-prototype-builtins': 'off', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': [ + 'error', + { + ignoreRestSiblings: true, + argsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^ignore', + }, + ], + '@typescript-eslint/no-explicit-any': 'warn', + }, + }, +]; diff --git a/experimental.d.ts b/experimental.d.ts index 420e6cb4..729e4109 100644 --- a/experimental.d.ts +++ b/experimental.d.ts @@ -1 +1 @@ -export * from './lib/experimental'; \ No newline at end of file +export * from './lib/experimental'; diff --git a/experimental.js b/experimental.js index 2404d976..6b51a299 100644 --- a/experimental.js +++ b/experimental.js @@ -1,17 +1,30 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __exportStar = (this && this.__exportStar) || function(m, exports) { - for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -__exportStar(require("./lib/experimental"), exports); \ No newline at end of file +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ('get' in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __exportStar = + (this && this.__exportStar) || + function (m, exports) { + for (var p in m) + if (p !== 'default' && !Object.prototype.hasOwnProperty.call(exports, p)) + __createBinding(exports, m, p); + }; +Object.defineProperty(exports, '__esModule', { value: true }); +__exportStar(require('./lib/experimental'), exports); diff --git a/gulpfile.js b/gulpfile.js index 3a739b4d..146e7669 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -6,20 +6,29 @@ const template = require('gulp-template'); // Compile all *.ejs files to pre-compiled templates and append *.js to the filename. gulp.task('templates', () => - gulp.src('./src/**/*.ejs') - .pipe(template.precompile({ - evaluate: /\{%([\s\S]+?)%\}/g, - interpolate: /\{\{([\s\S]+?)\}\}/g, - escape: /\{\{\{([\s\S]+?)\}\}\}/g, - variable: 'ctx' - })) - .pipe(insert.prepend('Object.defineProperty(exports, "__esModule", {\n' + - ' value: true\n' + - '});\n' + - 'exports.default=')) - .pipe(rename({ - extname: '.ejs.js' - })) + gulp + .src('./src/**/*.ejs') + .pipe( + template.precompile({ + evaluate: /\{%([\s\S]+?)%\}/g, + interpolate: /\{\{([\s\S]+?)\}\}/g, + escape: /\{\{\{([\s\S]+?)\}\}\}/g, + variable: 'ctx', + }), + ) + .pipe( + insert.prepend( + 'Object.defineProperty(exports, "__esModule", {\n' + + ' value: true\n' + + '});\n' + + 'exports.default=', + ), + ) + .pipe( + rename({ + extname: '.ejs.js', + }), + ) .pipe(gulp.dest('src')) - .pipe(gulp.dest('lib')) + .pipe(gulp.dest('lib')), ); diff --git a/index.html b/index.html index 70b56865..4f488c4d 100644 --- a/index.html +++ b/index.html @@ -1,263 +1,312 @@ - - - - - - - + + + - + } + + - -
-

Form.io Core Framework

-

A lightweight (15kB gzipped) and plain JavaScript JSON rendering framework and SDK for the Form.io platform.

-
-
+ +
+

Form.io Core Framework

+

+ A lightweight (15kB gzipped) and plain JavaScript JSON rendering framework and SDK for the + Form.io platform. +

+
+

Documentation

For the complete SDK documentation for this library:

SDK Documentation
-

The Form.io Core Framework provides two plain JavaScript libraries described as the following.

+

+ The Form.io Core Framework provides two plain JavaScript libraries described as the + following. +

JavaScript SDK
-

This is a library which allows JavaScript access to the Form.io API's.

-
<script src="https://cdn.jsdelivr.net/npm/@formio/base@latest/dist/formio.min.js"></script>
+

+ This is a library which allows JavaScript access to the Form.io API's. +

+
+
+<script src="https://cdn.jsdelivr.net/npm/@formio/base@latest/dist/formio.min.js"></script>
+
Example
-
+
- - JavaScript SDK Documentation + var formio = new Formio('https://examples.form.io/example'); + formio.loadForm().then(function (form) { + console.log(form); // Prints the JSON of this form. + formio.loadSubmissions().then(function (submissions) { + console.log(submissions); // Prints the submissions within this form. + }); + }); + + + JavaScript SDK Documentation
JSON Rendering Framework
-

This library provides a framework for rendering JSON schemas within a web application.

-
<script src="https://cdn.jsdelivr.net/npm/@formio/core@latest/dist/formio.core.min.js"></script>
- JSON Rendering Framework Documentation +

+ This library provides a framework for rendering JSON schemas within a web application. +

+
+
+<script src="https://cdn.jsdelivr.net/npm/@formio/core@latest/dist/formio.core.min.js"></script>
+
+ JSON Rendering Framework Documentation - - + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + +
ExamplesDemoExamplesDemo
-

Simple HTML Rendering

-

You can render a simple HTML element as follows:

-
-
-
- - -
-

Nested HTML Components

-

This allows you to created Nested HTML Components

-
-
-
- - -
-

Data Table Component

-

Provides an easy way to render a data table.

-
-
-
- - -
-

Input Component

-

Provides an easy way to add input components.

-
-
-
- - -
-

Input with Label

-

You can create an input with label by providing an htmlcontainer + html + input component.

-
-
-
- - -
-

Custom Component

-

Provides an easy way to create your own components.

-
-
-
- - -
+

Simple HTML Rendering

+

You can render a simple HTML element as follows:

+
+
+
+ + +
+

Nested HTML Components

+

This allows you to created Nested HTML Components

+
+
+
+ + +
+

Data Table Component

+

Provides an easy way to render a data table.

+
+
+
+ + +
+

Input Component

+

Provides an easy way to add input components.

+
+
+
+ + +
+

Input with Label

+

+ You can create an input with label by providing an htmlcontainer + html + input + component. +

+
+
+
+ + +
+

Custom Component

+

Provides an easy way to create your own components.

+
+
+
+ + +
-
- - +
+ diff --git a/package.json b/package.json index daea8b91..139cc89d 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,12 @@ "build:dev": "npx webpack --config config/webpack.config.js", "build:prod": "npx webpack --config config/webpack.prod.js", "clean": "rm -rf lib && rm -rf dist && rm -rf docs", - "build": "npm run clean && gulp templates && npm run docs && npm run lib && npm run build:dev && npm run build:prod", - "prepublish": "npm run build && npm run test", - "show-coverage": "open coverage/lcov-report/index.html" + "build": "yarn clean && gulp templates && yarn docs && yarn lib && yarn build:dev && yarn build:prod", + "prepublish": "yarn lint && yarn format && yarn build && yarn test", + "show-coverage": "open coverage/lcov-report/index.html", + "lint": "eslint src", + "format": "prettier --write .", + "prepare": "husky install" }, "repository": { "type": "git", @@ -53,12 +56,14 @@ ], "homepage": "https://github.com/formio/core#readme", "devDependencies": { + "@eslint/js": "^9.12.0", "@types/chai": "^4.3.16", "@types/chance": "^1.1.6", "@types/dompurify": "^3.0.5", "@types/fetch-mock": "^7.3.8", "@types/flatpickr": "^3.1.2", "@types/inputmask": "^5.0.7", + "@types/json-logic-js": "^2.0.7", "@types/lodash": "^4.17.4", "@types/lodash.template": "^4.5.3", "@types/mocha": "^10.0.4", @@ -67,18 +72,24 @@ "@types/uuid": "^9.0.8", "chai": "4.4.1", "chance": "^1.1.8", + "eslint": "^9.12.0", + "eslint-plugin-mocha": "^10.5.0", "fetch-mock": "^9.11.0", + "globals": "^15.11.0", "gulp": "^5.0.0", "gulp-insert": "^0.5.0", "gulp-rename": "^2.0.0", "gulp-template": "^5.0.0", + "husky": ">=6", "jsdom": "22.1.0", "jsdom-global": "^3.0.2", + "lint-staged": ">=10", "mocha": "^10.4.0", "mocha-jsdom": "^2.0.0", "mock-local-storage": "^1.1.20", "nyc": "^15.1.0", "power-assert": "^1.6.1", + "prettier": "^3.3.3", "sinon": "^17.0.2", "ts-loader": "^9.5.0", "ts-node": "^10.5.0", @@ -87,12 +98,11 @@ "tsconfig-paths-webpack-plugin": "^4.1.0", "typedoc": "^0.25.13", "typescript": "^5.4.5", + "typescript-eslint": "^8.8.1", "webpack": "^5.91.0", - "webpack-cli": "^5.1.4", - "written-number": "^0.11.1" + "webpack-cli": "^5.1.4" }, "dependencies": { - "@types/json-logic-js": "^2.0.7", "browser-cookies": "^1.2.0", "core-js": "^3.38.0", "dayjs": "^1.11.12", @@ -122,5 +132,9 @@ "src/types/**/*.ts" ], "all": true + }, + "lint-staged": { + "*.{js,mjs,cjs,ts}": "eslint src --cache --fix", + "*.{js,mjs,cjs,ts,css,md}": "prettier --write" } } diff --git a/src/ejs.d.ts b/src/ejs.d.ts index d094dbf1..a753e9c2 100644 --- a/src/ejs.d.ts +++ b/src/ejs.d.ts @@ -1,4 +1,4 @@ declare module '*.ejs' { - const value: string; - export default value -} \ No newline at end of file + const value: string; + export default value; +} diff --git a/src/error/FieldError.ts b/src/error/FieldError.ts index 7b65979f..b1730083 100644 --- a/src/error/FieldError.ts +++ b/src/error/FieldError.ts @@ -2,44 +2,52 @@ import { getComponentErrorField } from 'process/validation/util'; import { ValidationContext } from 'types'; type FieldErrorContext = ValidationContext & { - field?: string; - // TODO: the following are needed for for backwards compatibility, do we need this? - // * context.level will determine whether the `alert` template will display - // * context.hasLabel will determine how the error is displayed in the `alert` template - level?: string; - hasLabel?: boolean; - setting?: string | boolean | number; - // TODO: these are the custom error properties according to the inline docs in the builer - min?: string; - max?: string; - length?: string; - pattern?: string; - minCount?: string; - maxCount?: string; - minDate?: string; - maxDate?: string; - minYear?: string; - maxYear?: string; - regex?: string; + field?: string; + // TODO: the following are needed for for backwards compatibility, do we need this? + // * context.level will determine whether the `alert` template will display + // * context.hasLabel will determine how the error is displayed in the `alert` template + level?: string; + hasLabel?: boolean; + setting?: string | boolean | number; + // TODO: these are the custom error properties according to the inline docs in the builer + min?: string; + max?: string; + length?: string; + pattern?: string; + minCount?: string; + maxCount?: string; + minDate?: string; + maxDate?: string; + minYear?: string; + maxYear?: string; + regex?: string; }; export class FieldError { - context: FieldErrorContext - errorKeyOrMessage: string; - ruleName: string; - level?: string; - constructor(errorKeyOrMessage: string, context: FieldErrorContext, ruleName: string = errorKeyOrMessage) { - const { component, hasLabel = true, field = getComponentErrorField(component, context), level = 'error' } = context; - this.ruleName = ruleName; - if (context.component.validate?.customMessage) { - this.errorKeyOrMessage = context.component.validate.customMessage; - this.context = { ...context, hasLabel: false, field, level }; - } - else { - this.errorKeyOrMessage = errorKeyOrMessage; - this.context = { ...context, hasLabel, field }; - this.level = level; - } + context: FieldErrorContext; + errorKeyOrMessage: string; + ruleName: string; + level?: string; + constructor( + errorKeyOrMessage: string, + context: FieldErrorContext, + ruleName: string = errorKeyOrMessage, + ) { + const { + component, + hasLabel = true, + field = getComponentErrorField(component, context), + level = 'error', + } = context; + this.ruleName = ruleName; + if (context.component.validate?.customMessage) { + this.errorKeyOrMessage = context.component.validate.customMessage; + this.context = { ...context, hasLabel: false, field, level }; + } else { + this.errorKeyOrMessage = errorKeyOrMessage; + this.context = { ...context, hasLabel, field }; + this.level = level; } + } } export type InterpolateErrorFn = (text: string, context: FieldErrorContext) => string; diff --git a/src/error/ProcessorError.ts b/src/error/ProcessorError.ts index 7f3a882a..fce34267 100644 --- a/src/error/ProcessorError.ts +++ b/src/error/ProcessorError.ts @@ -1,10 +1,10 @@ -import { ProcessorContext } from "types"; +import { ProcessorContext } from 'types'; export class ProcessorError extends Error { - context: Omit, 'scope'>; - constructor(message: string, context: ProcessorContext, processor: string = 'unknown') { - super(message); - this.message = `${message}\nin ${processor} at ${context.path}`; - const { component, path, data, row } = context; - this.context = {component, path, data, row}; - } -}; + context: Omit, 'scope'>; + constructor(message: string, context: ProcessorContext, processor: string = 'unknown') { + super(message); + this.message = `${message}\nin ${processor} at ${context.path}`; + const { component, path, data, row } = context; + this.context = { component, path, data, row }; + } +} diff --git a/src/experimental/base/Components.ts b/src/experimental/base/Components.ts index 0a793d6d..01f3bba4 100644 --- a/src/experimental/base/Components.ts +++ b/src/experimental/base/Components.ts @@ -2,92 +2,91 @@ * Manages all of the components within the Form.io renderer. */ export class Components { - /** - * An array of Components available to be rendered. - */ - public static components: any = {}; - public static decorators: any = {}; + /** + * An array of Components available to be rendered. + */ + public static components: any = {}; + public static decorators: any = {}; - /** - * Gets a specific component type. - * - * @param type - * @param from - * @returns - */ - public static component(type: string, from: any = 'components') { - if ((Components as any)[from][type]) { - return (Components as any)[from][type]; - } - else { - return (Components as any)[from].component; - } + /** + * Gets a specific component type. + * + * @param type + * @param from + * @returns + */ + public static component(type: string, from: any = 'components') { + if ((Components as any)[from][type]) { + return (Components as any)[from][type]; + } else { + return (Components as any)[from].component; } + } - /** - * Create a new component. - * - * ```ts - * const htmlComp = Components.createComponent({ - * type: 'html', - * tag: 'p', - * content: 'This is a test.' - * }) - * ``` - * - * @param comp The component JSON you wish to create. - * @param options The options to pass to this component. - * @param data The data you wish to provide to this component. - */ - public static create(comp: any, options?: any, data?: any) { - return new (Components.component(comp.type))(comp, options, data); - } + /** + * Create a new component. + * + * ```ts + * const htmlComp = Components.createComponent({ + * type: 'html', + * tag: 'p', + * content: 'This is a test.' + * }) + * ``` + * + * @param comp The component JSON you wish to create. + * @param options The options to pass to this component. + * @param data The data you wish to provide to this component. + */ + public static create(comp: any, options?: any, data?: any) { + return new (Components.component(comp.type))(comp, options, data); + } - /** - * Adds a base decorator type component. - * - * @param baseComponent - * @param type - */ - public static addDecorator(decorator: any, type: string) { - Components.decorators[type] = decorator; - } + /** + * Adds a base decorator type component. + * + * @param baseComponent + * @param type + */ + public static addDecorator(decorator: any, type: string) { + Components.decorators[type] = decorator; + } - /** - * Adds a new component to the renderer. Can either be a component class or a component JSON - * to be imported. - * - * @param component - */ - public static addComponent(component: any, type: string) { - if (!component) { - return; - } - if (typeof component !== 'function') { - return Components.importComponent(component); - } - Components.components[type] = component; - return component; + /** + * Adds a new component to the renderer. Can either be a component class or a component JSON + * to be imported. + * + * @param component + */ + public static addComponent(component: any, type: string) { + if (!component) { + return; } - - /** - * Imports a new component based on the JSON decorator of that component. - * @param component - */ - public static importComponent(props: any = {}) { - const Decorator = Components.component(props.extends, 'decorators'); - @Decorator(props) - class ExtendedComponent {} - Components.addComponent(ExtendedComponent, props.type); + if (typeof component !== 'function') { + return Components.importComponent(component); } + Components.components[type] = component; + return component; + } - /** - * Sets the components used within this renderer. - * @param components - */ - public static setComponents(components: any) { - Object.assign(Components.components, components); - } + /** + * Imports a new component based on the JSON decorator of that component. + * @param component + */ + public static importComponent(props: any = {}) { + const Decorator = Components.component(props.extends, 'decorators'); + @Decorator(props) + class ExtendedComponent {} + Components.addComponent(ExtendedComponent, props.type); + } + + /** + * Sets the components used within this renderer. + * @param components + */ + public static setComponents(components: any) { + Object.assign(Components.components, components); + } } /** @@ -98,11 +97,6 @@ export class Components { * @param options * @param data */ -export function render( - element: HTMLElement, - component: any, - options: any = {}, - data: any = {} -) { - return Components.create(component, options, data).attach(element); +export function render(element: HTMLElement, component: any, options: any = {}, data: any = {}) { + return Components.create(component, options, data).attach(element); } diff --git a/src/experimental/base/array/ArrayComponent.ts b/src/experimental/base/array/ArrayComponent.ts index bbf496f9..331d1d7c 100644 --- a/src/experimental/base/array/ArrayComponent.ts +++ b/src/experimental/base/array/ArrayComponent.ts @@ -1,5 +1,5 @@ import { Components } from '../Components'; -import { NestedArrayModel, ModelDecoratorInterface, ModelInterface } from '../../model'; +import { NestedArrayModel, ModelDecoratorInterface, ModelInterface } from '../../model'; import { NestedComponent } from '../nested/NestedComponent'; /** * An array data type component. This provides a nested component that creates "rows" of data @@ -38,15 +38,15 @@ import { NestedComponent } from '../nested/NestedComponent'; * ``` */ export function ArrayComponent(props: any = {}): ModelDecoratorInterface { - if (!props.type) { - props.type = 'array'; - } - if (!props.model) { - props.model = NestedArrayModel; - } - return function(BaseClass?: ModelInterface) : ModelInterface { - return class ExtendedArrayComponent extends NestedComponent(props)(BaseClass) {} - }; + if (!props.type) { + props.type = 'array'; + } + if (!props.model) { + props.model = NestedArrayModel; + } + return function (BaseClass?: ModelInterface): ModelInterface { + return class ExtendedArrayComponent extends NestedComponent(props)(BaseClass) {}; + }; } Components.addDecorator(ArrayComponent, 'array'); diff --git a/src/experimental/base/array/__tests__/ArrayComponent.test.ts b/src/experimental/base/array/__tests__/ArrayComponent.test.ts index dcc5fb40..9ee811dd 100644 --- a/src/experimental/base/array/__tests__/ArrayComponent.test.ts +++ b/src/experimental/base/array/__tests__/ArrayComponent.test.ts @@ -1,266 +1,357 @@ import { assert } from 'chai'; import { ArrayComponent as ArrayComponentBase } from '../ArrayComponent'; import { comp1, comp2 } from './fixtures'; -const ArrayComponent = ArrayComponentBase()() +const ArrayComponent = ArrayComponentBase()(); -describe('ArrayComponent', () => { - it ('Should create a new Array Component', () => { - const data = {}; - new ArrayComponent(comp1, {}, data); - assert.deepEqual(data, {employees: []}); - }); +describe('ArrayComponent', function () { + it('Should create a new Array Component', function () { + const data = {}; + new ArrayComponent(comp1, {}, data); + assert.deepEqual(data, { employees: [] }); + }); - it ('Should create an Array Component with default data', () => { - let employees = [ - { - firstName: 'Joe', - lastName: 'Smith' - }, - { - firstName: 'Sally', - lastName: 'Thompson' - } - ]; - const data = { - employees: employees - }; - const arrComp = new ArrayComponent(comp1, {}, data); - assert.deepEqual(data, {employees: employees}); - assert.deepEqual(arrComp.dataValue, employees); - assert.equal(arrComp.rows.length, 2); - assert.equal(arrComp.rows[0].length, 2); - assert.equal(arrComp.rows[1].length, 2); - assert.equal(arrComp.components.length, 4); - assert.equal(arrComp.components[0].dataValue, 'Joe'); - assert.equal(arrComp.components[1].dataValue, 'Smith'); - assert.strictEqual(arrComp.rows[0][0], arrComp.components[0]); - assert.strictEqual(arrComp.rows[0][1], arrComp.components[1]); - assert.strictEqual(arrComp.rows[1][0], arrComp.components[2]); - assert.strictEqual(arrComp.rows[1][1], arrComp.components[3]); - assert.equal(arrComp.components[2].dataValue, 'Sally'); - assert.equal(arrComp.components[3].dataValue, 'Thompson'); - }); + it('Should create an Array Component with default data', function () { + const employees = [ + { + firstName: 'Joe', + lastName: 'Smith', + }, + { + firstName: 'Sally', + lastName: 'Thompson', + }, + ]; + const data = { + employees: employees, + }; + const arrComp = new ArrayComponent(comp1, {}, data); + assert.deepEqual(data, { employees: employees }); + assert.deepEqual(arrComp.dataValue, employees); + assert.equal(arrComp.rows.length, 2); + assert.equal(arrComp.rows[0].length, 2); + assert.equal(arrComp.rows[1].length, 2); + assert.equal(arrComp.components.length, 4); + assert.equal(arrComp.components[0].dataValue, 'Joe'); + assert.equal(arrComp.components[1].dataValue, 'Smith'); + assert.strictEqual(arrComp.rows[0][0], arrComp.components[0]); + assert.strictEqual(arrComp.rows[0][1], arrComp.components[1]); + assert.strictEqual(arrComp.rows[1][0], arrComp.components[2]); + assert.strictEqual(arrComp.rows[1][1], arrComp.components[3]); + assert.equal(arrComp.components[2].dataValue, 'Sally'); + assert.equal(arrComp.components[3].dataValue, 'Thompson'); + }); - it ('Should set the value of the sub components', () => { - const data = {}; - const arrComp = new ArrayComponent(comp1, {}, data); - let employees = [ - { - firstName: 'Joe', - lastName: 'Smith' - }, - { - firstName: 'Sally', - lastName: 'Thompson' - }, - { - firstName: 'Jane', - lastName: 'Doe' - } - ]; - arrComp.dataValue = employees; - assert.deepEqual(data, {employees: employees}); - assert.deepEqual(arrComp.dataValue, employees); - assert.equal(arrComp.rows.length, 3); - assert.equal(arrComp.rows[0].length, 2); - assert.equal(arrComp.rows[1].length, 2); - assert.equal(arrComp.rows[2].length, 2); - assert.equal(arrComp.components.length, 6); - assert.equal(arrComp.components[0].dataValue, 'Joe'); - assert.equal(arrComp.components[1].dataValue, 'Smith'); - assert.strictEqual(arrComp.rows[0][0], arrComp.components[0]); - assert.strictEqual(arrComp.rows[0][1], arrComp.components[1]); - assert.strictEqual(arrComp.rows[1][0], arrComp.components[2]); - assert.strictEqual(arrComp.rows[1][1], arrComp.components[3]); - assert.strictEqual(arrComp.rows[2][0], arrComp.components[4]); - assert.strictEqual(arrComp.rows[2][1], arrComp.components[5]); - assert.equal(arrComp.components[2].dataValue, 'Sally'); - assert.equal(arrComp.components[3].dataValue, 'Thompson'); - assert.equal(arrComp.components[4].dataValue, 'Jane'); - assert.equal(arrComp.components[5].dataValue, 'Doe'); + it('Should set the value of the sub components', function () { + const data = {}; + const arrComp = new ArrayComponent(comp1, {}, data); + let employees = [ + { + firstName: 'Joe', + lastName: 'Smith', + }, + { + firstName: 'Sally', + lastName: 'Thompson', + }, + { + firstName: 'Jane', + lastName: 'Doe', + }, + ]; + arrComp.dataValue = employees; + assert.deepEqual(data, { employees: employees }); + assert.deepEqual(arrComp.dataValue, employees); + assert.equal(arrComp.rows.length, 3); + assert.equal(arrComp.rows[0].length, 2); + assert.equal(arrComp.rows[1].length, 2); + assert.equal(arrComp.rows[2].length, 2); + assert.equal(arrComp.components.length, 6); + assert.equal(arrComp.components[0].dataValue, 'Joe'); + assert.equal(arrComp.components[1].dataValue, 'Smith'); + assert.strictEqual(arrComp.rows[0][0], arrComp.components[0]); + assert.strictEqual(arrComp.rows[0][1], arrComp.components[1]); + assert.strictEqual(arrComp.rows[1][0], arrComp.components[2]); + assert.strictEqual(arrComp.rows[1][1], arrComp.components[3]); + assert.strictEqual(arrComp.rows[2][0], arrComp.components[4]); + assert.strictEqual(arrComp.rows[2][1], arrComp.components[5]); + assert.equal(arrComp.components[2].dataValue, 'Sally'); + assert.equal(arrComp.components[3].dataValue, 'Thompson'); + assert.equal(arrComp.components[4].dataValue, 'Jane'); + assert.equal(arrComp.components[5].dataValue, 'Doe'); - // Ensure it removes rows. - employees = [ - { - firstName: 'Sally', - lastName: 'Thompson' - } - ]; - arrComp.dataValue = employees; - assert.deepEqual(data, {employees: employees}); - assert.deepEqual(arrComp.dataValue, employees); - assert.equal(arrComp.rows.length, 1); - assert.equal(arrComp.rows[0].length, 2); - assert.equal(arrComp.components.length, 2); - assert.strictEqual(arrComp.rows[0][0], arrComp.components[0]); - assert.strictEqual(arrComp.rows[0][1], arrComp.components[1]); - assert.equal(arrComp.components[0].dataValue, 'Sally'); - assert.equal(arrComp.components[1].dataValue, 'Thompson'); + // Ensure it removes rows. + employees = [ + { + firstName: 'Sally', + lastName: 'Thompson', + }, + ]; + arrComp.dataValue = employees; + assert.deepEqual(data, { employees: employees }); + assert.deepEqual(arrComp.dataValue, employees); + assert.equal(arrComp.rows.length, 1); + assert.equal(arrComp.rows[0].length, 2); + assert.equal(arrComp.components.length, 2); + assert.strictEqual(arrComp.rows[0][0], arrComp.components[0]); + assert.strictEqual(arrComp.rows[0][1], arrComp.components[1]); + assert.equal(arrComp.components[0].dataValue, 'Sally'); + assert.equal(arrComp.components[1].dataValue, 'Thompson'); - // Ensure it adds another row. - employees = [ - { - firstName: 'Sally', - lastName: 'Thompson' - }, - { - firstName: 'Joe', - lastName: 'Smith' - } - ]; - arrComp.dataValue = employees; - assert.deepEqual(data, {employees: employees}); - assert.deepEqual(arrComp.dataValue, employees); - assert.equal(arrComp.rows.length, 2); - assert.equal(arrComp.rows[0].length, 2); - assert.equal(arrComp.rows[1].length, 2); - assert.equal(arrComp.components.length, 4); - assert.equal(arrComp.components[0].dataValue, 'Sally'); - assert.equal(arrComp.components[1].dataValue, 'Thompson'); - assert.strictEqual(arrComp.rows[0][0], arrComp.components[0]); - assert.strictEqual(arrComp.rows[0][1], arrComp.components[1]); - assert.strictEqual(arrComp.rows[1][0], arrComp.components[2]); - assert.strictEqual(arrComp.rows[1][1], arrComp.components[3]); - assert.equal(arrComp.components[2].dataValue, 'Joe'); - assert.equal(arrComp.components[3].dataValue, 'Smith'); - }); + // Ensure it adds another row. + employees = [ + { + firstName: 'Sally', + lastName: 'Thompson', + }, + { + firstName: 'Joe', + lastName: 'Smith', + }, + ]; + arrComp.dataValue = employees; + assert.deepEqual(data, { employees: employees }); + assert.deepEqual(arrComp.dataValue, employees); + assert.equal(arrComp.rows.length, 2); + assert.equal(arrComp.rows[0].length, 2); + assert.equal(arrComp.rows[1].length, 2); + assert.equal(arrComp.components.length, 4); + assert.equal(arrComp.components[0].dataValue, 'Sally'); + assert.equal(arrComp.components[1].dataValue, 'Thompson'); + assert.strictEqual(arrComp.rows[0][0], arrComp.components[0]); + assert.strictEqual(arrComp.rows[0][1], arrComp.components[1]); + assert.strictEqual(arrComp.rows[1][0], arrComp.components[2]); + assert.strictEqual(arrComp.rows[1][1], arrComp.components[3]); + assert.equal(arrComp.components[2].dataValue, 'Joe'); + assert.equal(arrComp.components[3].dataValue, 'Smith'); + }); - const employees = [ + const employees = [ + { + firstName: 'Joe', + lastName: 'Smith', + department: { + name: 'HR', + phoneNumber: '555-123-4567', + }, + children: [ { - firstName: 'Joe', - lastName: 'Smith', - department: { - name: 'HR', - phoneNumber: '555-123-4567' - }, - children: [ - { - firstName: 'Joe Jr.', - dob: '5-17-2008' - }, - { - firstName: 'Joey', - dob: '12-2-2010' - } - ] + firstName: 'Joe Jr.', + dob: '5-17-2008', }, { - firstName: 'Sally', - lastName: 'Thompson', - department: { - name: 'Sales', - phoneNumber: '123-456-7890' - }, - children: [ - { - firstName: 'Harry', - dob: '1-23-2002' - }, - { - firstName: 'Sue', - dob: '3-23-2010' - }, - { - firstName: 'Stuart', - dob: '9-23-2014' - } - ] - } - ]; - it ('Should allow complex data structures', () => { - const data = {employees}; - const arrComp = new ArrayComponent(comp2, {}, data); - assert.deepEqual(data, {employees: employees}); - assert.deepEqual(arrComp.dataValue, employees); - assert.equal(arrComp.rows.length, 2); - assert.equal(arrComp.rows[0].length, 4); - assert.equal(arrComp.rows[1].length, 4); - assert.equal(arrComp.components.length, 8); - assert.strictEqual(arrComp.rows[0][0], arrComp.components[0]); - assert.strictEqual(arrComp.rows[0][1], arrComp.components[1]); - assert.strictEqual(arrComp.rows[0][2], arrComp.components[2]); - assert.strictEqual(arrComp.rows[0][3], arrComp.components[3]); - assert.strictEqual(arrComp.rows[1][0], arrComp.components[4]); - assert.strictEqual(arrComp.rows[1][1], arrComp.components[5]); - assert.strictEqual(arrComp.rows[1][2], arrComp.components[6]); - assert.strictEqual(arrComp.rows[1][3], arrComp.components[7]); - assert.equal(arrComp.components[0].dataValue, employees[0].firstName); - assert.equal(arrComp.components[1].dataValue, employees[0].lastName); - assert.equal(arrComp.components[2].dataValue, employees[0].department); - assert.equal((arrComp.components[2] as any).components.length, 2); - assert.equal((arrComp.components[2] as any).components[0].dataValue, employees[0].department.name); - assert.equal((arrComp.components[2] as any).components[1].dataValue, employees[0].department.phoneNumber); - assert.equal(arrComp.components[3].dataValue, employees[0].children); - assert.equal((arrComp.components[3] as any).components.length, 4); - assert.equal((arrComp.components[3] as any).components[0].dataValue, employees[0].children[0].firstName); - assert.equal((arrComp.components[3] as any).components[1].dataValue, employees[0].children[0].dob); - assert.equal((arrComp.components[3] as any).components[2].dataValue, employees[0].children[1].firstName); - assert.equal((arrComp.components[3] as any).components[3].dataValue, employees[0].children[1].dob); - assert.equal(arrComp.components[4].dataValue, employees[1].firstName); - assert.equal(arrComp.components[5].dataValue, employees[1].lastName); - assert.equal(arrComp.components[6].dataValue, employees[1].department); - assert.equal((arrComp.components[6] as any).components.length, 2); - assert.equal((arrComp.components[6] as any).components[0].dataValue, employees[1].department.name); - assert.equal((arrComp.components[6] as any).components[1].dataValue, employees[1].department.phoneNumber); - assert.equal(arrComp.components[7].dataValue, employees[1].children); - assert.equal((arrComp.components[7] as any).components.length, 6); - assert.equal((arrComp.components[7] as any).components[0].dataValue, employees[1].children[0].firstName); - assert.equal((arrComp.components[7] as any).components[1].dataValue, employees[1].children[0].dob); - assert.equal((arrComp.components[7] as any).components[2].dataValue, employees[1].children[1].firstName); - assert.equal((arrComp.components[7] as any).components[3].dataValue, employees[1].children[1].dob); - assert.equal((arrComp.components[7] as any).components[4].dataValue, employees[1].children[2].firstName); - assert.equal((arrComp.components[7] as any).components[5].dataValue, employees[1].children[2].dob); - }); + firstName: 'Joey', + dob: '12-2-2010', + }, + ], + }, + { + firstName: 'Sally', + lastName: 'Thompson', + department: { + name: 'Sales', + phoneNumber: '123-456-7890', + }, + children: [ + { + firstName: 'Harry', + dob: '1-23-2002', + }, + { + firstName: 'Sue', + dob: '3-23-2010', + }, + { + firstName: 'Stuart', + dob: '9-23-2014', + }, + ], + }, + ]; + + it('Should allow complex data structures', function () { + const data = { employees }; + const arrComp = new ArrayComponent(comp2, {}, data); + assert.deepEqual(data, { employees: employees }); + assert.deepEqual(arrComp.dataValue, employees); + assert.equal(arrComp.rows.length, 2); + assert.equal(arrComp.rows[0].length, 4); + assert.equal(arrComp.rows[1].length, 4); + assert.equal(arrComp.components.length, 8); + assert.strictEqual(arrComp.rows[0][0], arrComp.components[0]); + assert.strictEqual(arrComp.rows[0][1], arrComp.components[1]); + assert.strictEqual(arrComp.rows[0][2], arrComp.components[2]); + assert.strictEqual(arrComp.rows[0][3], arrComp.components[3]); + assert.strictEqual(arrComp.rows[1][0], arrComp.components[4]); + assert.strictEqual(arrComp.rows[1][1], arrComp.components[5]); + assert.strictEqual(arrComp.rows[1][2], arrComp.components[6]); + assert.strictEqual(arrComp.rows[1][3], arrComp.components[7]); + assert.equal(arrComp.components[0].dataValue, employees[0].firstName); + assert.equal(arrComp.components[1].dataValue, employees[0].lastName); + assert.equal(arrComp.components[2].dataValue, employees[0].department); + assert.equal((arrComp.components[2] as any).components.length, 2); + assert.equal( + (arrComp.components[2] as any).components[0].dataValue, + employees[0].department.name, + ); + assert.equal( + (arrComp.components[2] as any).components[1].dataValue, + employees[0].department.phoneNumber, + ); + assert.equal(arrComp.components[3].dataValue, employees[0].children); + assert.equal((arrComp.components[3] as any).components.length, 4); + assert.equal( + (arrComp.components[3] as any).components[0].dataValue, + employees[0].children[0].firstName, + ); + assert.equal( + (arrComp.components[3] as any).components[1].dataValue, + employees[0].children[0].dob, + ); + assert.equal( + (arrComp.components[3] as any).components[2].dataValue, + employees[0].children[1].firstName, + ); + assert.equal( + (arrComp.components[3] as any).components[3].dataValue, + employees[0].children[1].dob, + ); + assert.equal(arrComp.components[4].dataValue, employees[1].firstName); + assert.equal(arrComp.components[5].dataValue, employees[1].lastName); + assert.equal(arrComp.components[6].dataValue, employees[1].department); + assert.equal((arrComp.components[6] as any).components.length, 2); + assert.equal( + (arrComp.components[6] as any).components[0].dataValue, + employees[1].department.name, + ); + assert.equal( + (arrComp.components[6] as any).components[1].dataValue, + employees[1].department.phoneNumber, + ); + assert.equal(arrComp.components[7].dataValue, employees[1].children); + assert.equal((arrComp.components[7] as any).components.length, 6); + assert.equal( + (arrComp.components[7] as any).components[0].dataValue, + employees[1].children[0].firstName, + ); + assert.equal( + (arrComp.components[7] as any).components[1].dataValue, + employees[1].children[0].dob, + ); + assert.equal( + (arrComp.components[7] as any).components[2].dataValue, + employees[1].children[1].firstName, + ); + assert.equal( + (arrComp.components[7] as any).components[3].dataValue, + employees[1].children[1].dob, + ); + assert.equal( + (arrComp.components[7] as any).components[4].dataValue, + employees[1].children[2].firstName, + ); + assert.equal( + (arrComp.components[7] as any).components[5].dataValue, + employees[1].children[2].dob, + ); + }); - it ('Should be able to set complex data structures.', () => { - const data = {}; - const arrComp = new ArrayComponent(comp2, {}, data); - arrComp.dataValue = employees; - assert.deepEqual(data, {employees: employees}); - assert.deepEqual(arrComp.dataValue, employees); - assert.equal(arrComp.rows.length, 2); - assert.equal(arrComp.rows[0].length, 4); - assert.equal(arrComp.rows[1].length, 4); - assert.equal(arrComp.components.length, 8); - assert.strictEqual(arrComp.rows[0][0], arrComp.components[0]); - assert.strictEqual(arrComp.rows[0][1], arrComp.components[1]); - assert.strictEqual(arrComp.rows[0][2], arrComp.components[2]); - assert.strictEqual(arrComp.rows[0][3], arrComp.components[3]); - assert.strictEqual(arrComp.rows[1][0], arrComp.components[4]); - assert.strictEqual(arrComp.rows[1][1], arrComp.components[5]); - assert.strictEqual(arrComp.rows[1][2], arrComp.components[6]); - assert.strictEqual(arrComp.rows[1][3], arrComp.components[7]); - assert.equal(arrComp.components[0].dataValue, employees[0].firstName); - assert.equal(arrComp.components[1].dataValue, employees[0].lastName); - assert.equal(arrComp.components[2].dataValue, employees[0].department); - assert.equal((arrComp.components[2] as any).components.length, 2); - assert.equal((arrComp.components[2] as any).components[0].dataValue, employees[0].department.name); - assert.equal((arrComp.components[2] as any).components[1].dataValue, employees[0].department.phoneNumber); - assert.equal(arrComp.components[3].dataValue, employees[0].children); - assert.equal((arrComp.components[3] as any).components.length, 4); - assert.equal((arrComp.components[3] as any).components[0].dataValue, employees[0].children[0].firstName); - assert.equal((arrComp.components[3] as any).components[1].dataValue, employees[0].children[0].dob); - assert.equal((arrComp.components[3] as any).components[2].dataValue, employees[0].children[1].firstName); - assert.equal((arrComp.components[3] as any).components[3].dataValue, employees[0].children[1].dob); - assert.equal(arrComp.components[4].dataValue, employees[1].firstName); - assert.equal(arrComp.components[5].dataValue, employees[1].lastName); - assert.equal(arrComp.components[6].dataValue, employees[1].department); - assert.equal((arrComp.components[6] as any).components.length, 2); - assert.equal((arrComp.components[6] as any).components[0].dataValue, employees[1].department.name); - assert.equal((arrComp.components[6] as any).components[1].dataValue, employees[1].department.phoneNumber); - assert.equal(arrComp.components[7].dataValue, employees[1].children); - assert.equal((arrComp.components[7] as any).components.length, 6); - assert.equal((arrComp.components[7] as any).components[0].dataValue, employees[1].children[0].firstName); - assert.equal((arrComp.components[7] as any).components[1].dataValue, employees[1].children[0].dob); - assert.equal((arrComp.components[7] as any).components[2].dataValue, employees[1].children[1].firstName); - assert.equal((arrComp.components[7] as any).components[3].dataValue, employees[1].children[1].dob); - assert.equal((arrComp.components[7] as any).components[4].dataValue, employees[1].children[2].firstName); - assert.equal((arrComp.components[7] as any).components[5].dataValue, employees[1].children[2].dob); + it('Should be able to set complex data structures.', function () { + const data = {}; + const arrComp = new ArrayComponent(comp2, {}, data); + arrComp.dataValue = employees; + assert.deepEqual(data, { employees: employees }); + assert.deepEqual(arrComp.dataValue, employees); + assert.equal(arrComp.rows.length, 2); + assert.equal(arrComp.rows[0].length, 4); + assert.equal(arrComp.rows[1].length, 4); + assert.equal(arrComp.components.length, 8); + assert.strictEqual(arrComp.rows[0][0], arrComp.components[0]); + assert.strictEqual(arrComp.rows[0][1], arrComp.components[1]); + assert.strictEqual(arrComp.rows[0][2], arrComp.components[2]); + assert.strictEqual(arrComp.rows[0][3], arrComp.components[3]); + assert.strictEqual(arrComp.rows[1][0], arrComp.components[4]); + assert.strictEqual(arrComp.rows[1][1], arrComp.components[5]); + assert.strictEqual(arrComp.rows[1][2], arrComp.components[6]); + assert.strictEqual(arrComp.rows[1][3], arrComp.components[7]); + assert.equal(arrComp.components[0].dataValue, employees[0].firstName); + assert.equal(arrComp.components[1].dataValue, employees[0].lastName); + assert.equal(arrComp.components[2].dataValue, employees[0].department); + assert.equal((arrComp.components[2] as any).components.length, 2); + assert.equal( + (arrComp.components[2] as any).components[0].dataValue, + employees[0].department.name, + ); + assert.equal( + (arrComp.components[2] as any).components[1].dataValue, + employees[0].department.phoneNumber, + ); + assert.equal(arrComp.components[3].dataValue, employees[0].children); + assert.equal((arrComp.components[3] as any).components.length, 4); + assert.equal( + (arrComp.components[3] as any).components[0].dataValue, + employees[0].children[0].firstName, + ); + assert.equal( + (arrComp.components[3] as any).components[1].dataValue, + employees[0].children[0].dob, + ); + assert.equal( + (arrComp.components[3] as any).components[2].dataValue, + employees[0].children[1].firstName, + ); + assert.equal( + (arrComp.components[3] as any).components[3].dataValue, + employees[0].children[1].dob, + ); + assert.equal(arrComp.components[4].dataValue, employees[1].firstName); + assert.equal(arrComp.components[5].dataValue, employees[1].lastName); + assert.equal(arrComp.components[6].dataValue, employees[1].department); + assert.equal((arrComp.components[6] as any).components.length, 2); + assert.equal( + (arrComp.components[6] as any).components[0].dataValue, + employees[1].department.name, + ); + assert.equal( + (arrComp.components[6] as any).components[1].dataValue, + employees[1].department.phoneNumber, + ); + assert.equal(arrComp.components[7].dataValue, employees[1].children); + assert.equal((arrComp.components[7] as any).components.length, 6); + assert.equal( + (arrComp.components[7] as any).components[0].dataValue, + employees[1].children[0].firstName, + ); + assert.equal( + (arrComp.components[7] as any).components[1].dataValue, + employees[1].children[0].dob, + ); + assert.equal( + (arrComp.components[7] as any).components[2].dataValue, + employees[1].children[1].firstName, + ); + assert.equal( + (arrComp.components[7] as any).components[3].dataValue, + employees[1].children[1].dob, + ); + assert.equal( + (arrComp.components[7] as any).components[4].dataValue, + employees[1].children[2].firstName, + ); + assert.equal( + (arrComp.components[7] as any).components[5].dataValue, + employees[1].children[2].dob, + ); - // Ensure parent and root elements are all set correctly. - assert.strictEqual((arrComp.components[7] as any).components[0].parent, (arrComp.components[7] as any)); - assert.strictEqual((arrComp.components[7] as any).components[1].parent, (arrComp.components[7] as any)); - assert.strictEqual((arrComp.components[7] as any).components[0].root, arrComp); - assert.strictEqual((arrComp.components[7] as any).parent, arrComp); - }); + // Ensure parent and root elements are all set correctly. + assert.strictEqual( + (arrComp.components[7] as any).components[0].parent, + arrComp.components[7] as any, + ); + assert.strictEqual( + (arrComp.components[7] as any).components[1].parent, + arrComp.components[7] as any, + ); + assert.strictEqual((arrComp.components[7] as any).components[0].root, arrComp); + assert.strictEqual((arrComp.components[7] as any).parent, arrComp); + }); }); diff --git a/src/experimental/base/array/__tests__/fixtures/comp1.ts b/src/experimental/base/array/__tests__/fixtures/comp1.ts index 0478077c..a986d637 100644 --- a/src/experimental/base/array/__tests__/fixtures/comp1.ts +++ b/src/experimental/base/array/__tests__/fixtures/comp1.ts @@ -1,14 +1,14 @@ export default { - type: 'array', - key: 'employees', - components: [ - { - type: 'component', - key: 'firstName' - }, - { - type: 'component', - key: 'lastName' - } - ] -}; \ No newline at end of file + type: 'array', + key: 'employees', + components: [ + { + type: 'component', + key: 'firstName', + }, + { + type: 'component', + key: 'lastName', + }, + ], +}; diff --git a/src/experimental/base/array/__tests__/fixtures/comp2.ts b/src/experimental/base/array/__tests__/fixtures/comp2.ts index bb3edd19..d90feb27 100644 --- a/src/experimental/base/array/__tests__/fixtures/comp2.ts +++ b/src/experimental/base/array/__tests__/fixtures/comp2.ts @@ -1,42 +1,42 @@ export default { - type: 'array', - key: 'employees', - components: [ + type: 'array', + key: 'employees', + components: [ + { + type: 'component', + key: 'firstName', + }, + { + type: 'component', + key: 'lastName', + }, + { + type: 'data', + key: 'department', + components: [ { - type: 'component', - key: 'firstName' + type: 'component', + key: 'name', }, { - type: 'component', - key: 'lastName' + type: 'component', + key: 'phoneNumber', }, + ], + }, + { + type: 'array', + key: 'children', + components: [ { - type: 'data', - key: 'department', - components: [ - { - type: 'component', - key: 'name' - }, - { - type: 'component', - key: 'phoneNumber' - } - ] + type: 'component', + key: 'firstName', }, { - type: 'array', - key: 'children', - components: [ - { - type: 'component', - key: 'firstName' - }, - { - type: 'component', - key: 'dob' - } - ] - } - ] -}; \ No newline at end of file + type: 'component', + key: 'dob', + }, + ], + }, + ], +}; diff --git a/src/experimental/base/array/__tests__/fixtures/index.ts b/src/experimental/base/array/__tests__/fixtures/index.ts index bdd99755..7c38dd80 100644 --- a/src/experimental/base/array/__tests__/fixtures/index.ts +++ b/src/experimental/base/array/__tests__/fixtures/index.ts @@ -1,3 +1,3 @@ import comp1 from './comp1'; import comp2 from './comp2'; -export { comp1, comp2 }; \ No newline at end of file +export { comp1, comp2 }; diff --git a/src/experimental/base/component/Component.ts b/src/experimental/base/component/Component.ts index 4eb0cef9..2f69e059 100644 --- a/src/experimental/base/component/Component.ts +++ b/src/experimental/base/component/Component.ts @@ -4,378 +4,386 @@ import { Template } from '../../template'; import { Evaluator } from 'utils/Evaluator'; import * as dom from 'utils/dom'; import { sanitize } from 'utils/sanitize'; -import { Model, ModelDecoratorInterface, ModelInterface } from '../../model'; +import { Model, ModelDecoratorInterface, ModelInterface } from '../../model'; /** * The component JSON schema. */ export interface ComponentSchema { - type: string, - key: string, - label?: string + type: string; + key: string; + label?: string; } /** * Component options. */ export interface ComponentOptions { - language?: string, - i18n?: any, - namespace?: string, - hooks?: any, - template?: string, - noInit?: boolean + language?: string; + i18n?: any; + namespace?: string; + hooks?: any; + template?: string; + noInit?: boolean; } export interface ComponentInterface { - new (component?: any, options?: any, data?: any): any; + new (component?: any, options?: any, data?: any): any; } -export function Component(props: any = {}) : ModelDecoratorInterface { - props = merge({ - type: 'component', - template: false, - schema: { - persistent: true, - protected: false, - } - }, props); - props.schema.type = props.type; - const ModelClass = props.model || Model; - return function(BaseClass?: ModelInterface) : ModelInterface { - return class ExtendedComponent extends ModelClass(props)(BaseClass) { - /** - * The DOM Element associated with this component. - */ - public element?: HTMLElement; - - /** - * Boolean to let us know if this component is attached to the DOM or not. - */ - public attached: boolean = false; - - /** - * The DOM element references used for component logic. - */ - public refs: any = {}; - - /** - * The template to render for this component. - */ - public template: any = props.template; - - /** - * An array of attached listeners. - */ - public attachedListeners: Array = []; - - - public get defaultOptions(): any { - return { - language: 'en', - namespace: 'formio' - }; - } - - public get defaultTemplate(): any { - return (ctx: any) => `${ctx.t('Unknown Component')}`; - } - - /** - * Interpolate a template string. - * @param template - The template string to interpolate. - * @param context - The context variables to pass to the interpolation. - */ - public interpolate(template: string, context: any) { - return Evaluator.interpolate(template, context); - } - - /** - * The rendering context. - * @param context - The existing contexts from parent classes. - */ - public renderContext(context: any = {}) { - if (super.renderContext) { - return super.renderContext(context); - } - return context; - } - - /** - * Performs an evaluation using the evaluation context of this component. - * - * @param func - * @param args - * @param ret - * @param tokenize - * @return {*} - */ - public evaluate(func: any, args: any = {}, ret: any = '', tokenize: boolean = false) { - return Evaluator.evaluate(func, this.evalContext(args), ret, tokenize); - } - - /** - * Renders this component as an HTML string. - */ - public render(context: any = {}): string { - if (super.render) { - return super.render(context); - } - return this.renderTemplate((this.template || this.component.type), this.renderContext(context)); - } - - /** - * Returns the template references. - */ - public getRefs() { - if (super.getRefs) { - return super.getRefs(); - } - return {}; - } - - /** - * Loads the elemement references. - * @param element - */ - loadRefs(element: HTMLElement) { - const refs: any = this.getRefs(); - for (const ref in refs) { - if (refs[ref] === 'single') { - this.refs[ref] = element.querySelector(`[ref="${ref}"]`); - } - else { - this.refs[ref] = element.querySelectorAll(`[ref="${ref}"]`); - } - } - } - - /** - * Renders the component and then attaches this component to the HTMLElement. - * @param element - */ - public async attach(element?: HTMLElement | undefined) { - if (this.element && !element) { - element = this.element; - } - if (!element) { - return this; - } - const parent = element.parentNode; - if (!parent) { - return this; - } - const index = Array.prototype.indexOf.call(parent.children, element); - element.outerHTML = String(this.sanitize(this.render())); - element = parent.children[index] as HTMLElement; - this.element = element; - this.loadRefs(this.element); - if (super.attach) { - await super.attach(element); - } - this.attached = true; - return this; - } - - /** - * Redraw this component. - * @returns - */ - public async redraw() { - if (this.element) { - this.clear(); - return this.attach(); - } - } - - /** - * Sanitize an html string. - * - * @param string - * @returns {*} - */ - sanitize(dirty: string): (TrustedHTML | string) { - return sanitize(dirty, this.options); - } - - /** - * Get all available translations. - */ - public get translations(): any { - if ( - this.options.language && - this.options.i18n && - this.options.i18n[this.options.language] - ) { - return this.options.i18n[this.options.language]; - } - return {}; - } - - /** - * Tranlation method to translate a string being rendered. - * @param str - */ - public t(str: string): string { - if (this.translations[str]) { - return this.translations[str]; - } - return str; - } - - /** - * The evaluation context for interpolations. - * @param extend - */ - public evalContext(extend: any = {}) { - return Object.assign({ - instance: this, - component: this.component, - options: this.options, - row: this.data, - data: this.root ? this.root.data : this.data, - rowIndex: this.rowIndex, - value: () => this.dataValue, - t: (str: string) => this.t(str) - }, extend); - } - - /** - * Render a template with provided context. - * @param name - * @param ctx - */ - public renderTemplate(name: any, ctx: any = {}): string { - return Template.render(name, this.evalContext(ctx), 'html', this.defaultTemplate); - } - - /** - * Determines if the value of this component is redacted from the user as if it is coming from the server, but is protected. - * - * @return {boolean|*} - */ - isValueRedacted() { - return ( - this.component.protected || - !this.component.persistent || - (this.component.persistent === 'client-only') - ); - } - - /** - * Sets the data value and updates the view representation. - * @param value - */ - public setValue(value: any): boolean { - let changed = false; - if (super.setValue) { - changed = super.setValue(value); - } - return this.updateValue(value) || changed; - } - - /** - * Returns the main HTML Element for this component. - */ - getElement(): (HTMLElement | undefined) { - return this.element; - } - - /** - * Remove all event handlers. - */ - detach() { - this.refs = {}; - this.attached = false; - this.removeAttachedListeners(); - if (super.detach) { - super.detach(); - } - } - - /** - * Clear an element. - */ - clear() { - this.detach(); - dom.empty(this.getElement()); - if (super.clear) { - super.clear(); - } - } - - /** - * Appends an element to this component. - * @param element - */ - append(element: (HTMLElement | undefined)) { - dom.appendTo(element, this.element); - } - - /** - * Prepends an element to this component. - * @param element - */ - prepend(element: (HTMLElement | undefined)) { - dom.prependTo(element, this.element); - } - - /** - * Removes an element from this component. - * @param element - */ - removeChild(element: (HTMLElement | undefined)) { - dom.removeChildFrom(element, this.element); - } - - /** - * Wrapper method to add an event listener to an HTML element. - * - * @param obj - * The DOM element to add the event to. - * @param type - * The event name to add. - * @param func - * The callback function to be executed when the listener is triggered. - * @param persistent - * If this listener should persist beyond "destroy" commands. - */ - addEventListener(obj: any, type: string, func: any) { - if (!obj) { - return; - } - if ('addEventListener' in obj) { - obj.addEventListener(type, func, false); - } - else if ('attachEvent' in obj) { - obj.attachEvent(`on${type}`, func); - } - this.attachedListeners.push({ obj, type, func }); - return this; - } - - /** - * Remove all the attached listeners. - */ - removeAttachedListeners() { - this.attachedListeners.forEach((item) => this.removeEventListener(item.obj, item.type, item.func)); - this.attachedListeners = []; - } - - /** - * Remove an event listener from the object. - * - * @param obj - * @param type - */ - removeEventListener(obj: any, type: string, func: any) { - if (obj) { - obj.removeEventListener(type, func); - } - return this; - } +export function Component(props: any = {}): ModelDecoratorInterface { + props = merge( + { + type: 'component', + template: false, + schema: { + persistent: true, + protected: false, + }, + }, + props, + ); + props.schema.type = props.type; + const ModelClass = props.model || Model; + return function (BaseClass?: ModelInterface): ModelInterface { + return class ExtendedComponent extends ModelClass(props)(BaseClass) { + /** + * The DOM Element associated with this component. + */ + public element?: HTMLElement; + + /** + * Boolean to let us know if this component is attached to the DOM or not. + */ + public attached: boolean = false; + + /** + * The DOM element references used for component logic. + */ + public refs: any = {}; + + /** + * The template to render for this component. + */ + public template: any = props.template; + + /** + * An array of attached listeners. + */ + public attachedListeners: Array = []; + + public get defaultOptions(): any { + return { + language: 'en', + namespace: 'formio', }; - } + } + + public get defaultTemplate(): any { + return (ctx: any) => `${ctx.t('Unknown Component')}`; + } + + /** + * Interpolate a template string. + * @param template - The template string to interpolate. + * @param context - The context variables to pass to the interpolation. + */ + public interpolate(template: string, context: any) { + return Evaluator.interpolate(template, context); + } + + /** + * The rendering context. + * @param context - The existing contexts from parent classes. + */ + public renderContext(context: any = {}) { + if (super.renderContext) { + return super.renderContext(context); + } + return context; + } + + /** + * Performs an evaluation using the evaluation context of this component. + * + * @param func + * @param args + * @param ret + * @param tokenize + * @return {*} + */ + public evaluate(func: any, args: any = {}, ret: any = '', tokenize: boolean = false) { + return Evaluator.evaluate(func, this.evalContext(args), ret, tokenize); + } + + /** + * Renders this component as an HTML string. + */ + public render(context: any = {}): string { + if (super.render) { + return super.render(context); + } + return this.renderTemplate( + this.template || this.component.type, + this.renderContext(context), + ); + } + + /** + * Returns the template references. + */ + public getRefs() { + if (super.getRefs) { + return super.getRefs(); + } + return {}; + } + + /** + * Loads the elemement references. + * @param element + */ + loadRefs(element: HTMLElement) { + const refs: any = this.getRefs(); + for (const ref in refs) { + if (refs[ref] === 'single') { + this.refs[ref] = element.querySelector(`[ref="${ref}"]`); + } else { + this.refs[ref] = element.querySelectorAll(`[ref="${ref}"]`); + } + } + } + + /** + * Renders the component and then attaches this component to the HTMLElement. + * @param element + */ + public async attach(element?: HTMLElement | undefined) { + if (this.element && !element) { + element = this.element; + } + if (!element) { + return this; + } + const parent = element.parentNode; + if (!parent) { + return this; + } + const index = Array.prototype.indexOf.call(parent.children, element); + element.outerHTML = String(this.sanitize(this.render())); + element = parent.children[index] as HTMLElement; + this.element = element; + this.loadRefs(this.element); + if (super.attach) { + await super.attach(element); + } + this.attached = true; + return this; + } + + /** + * Redraw this component. + * @returns + */ + public async redraw() { + if (this.element) { + this.clear(); + return this.attach(); + } + } + + /** + * Sanitize an html string. + * + * @param string + * @returns {*} + */ + sanitize(dirty: string): TrustedHTML | string { + return sanitize(dirty, this.options); + } + + /** + * Get all available translations. + */ + public get translations(): any { + if ( + this.options.language && + this.options.i18n && + this.options.i18n[this.options.language] + ) { + return this.options.i18n[this.options.language]; + } + return {}; + } + + /** + * Tranlation method to translate a string being rendered. + * @param str + */ + public t(str: string): string { + if (this.translations[str]) { + return this.translations[str]; + } + return str; + } + + /** + * The evaluation context for interpolations. + * @param extend + */ + public evalContext(extend: any = {}) { + return Object.assign( + { + instance: this, + component: this.component, + options: this.options, + row: this.data, + data: this.root ? this.root.data : this.data, + rowIndex: this.rowIndex, + value: () => this.dataValue, + t: (str: string) => this.t(str), + }, + extend, + ); + } + + /** + * Render a template with provided context. + * @param name + * @param ctx + */ + public renderTemplate(name: any, ctx: any = {}): string { + return Template.render(name, this.evalContext(ctx), 'html', this.defaultTemplate); + } + + /** + * Determines if the value of this component is redacted from the user as if it is coming from the server, but is protected. + * + * @return {boolean|*} + */ + isValueRedacted() { + return ( + this.component.protected || + !this.component.persistent || + this.component.persistent === 'client-only' + ); + } + + /** + * Sets the data value and updates the view representation. + * @param value + */ + public setValue(value: any): boolean { + let changed = false; + if (super.setValue) { + changed = super.setValue(value); + } + return this.updateValue(value) || changed; + } + + /** + * Returns the main HTML Element for this component. + */ + getElement(): HTMLElement | undefined { + return this.element; + } + + /** + * Remove all event handlers. + */ + detach() { + this.refs = {}; + this.attached = false; + this.removeAttachedListeners(); + if (super.detach) { + super.detach(); + } + } + + /** + * Clear an element. + */ + clear() { + this.detach(); + dom.empty(this.getElement()); + if (super.clear) { + super.clear(); + } + } + + /** + * Appends an element to this component. + * @param element + */ + append(element: HTMLElement | undefined) { + dom.appendTo(element, this.element); + } + + /** + * Prepends an element to this component. + * @param element + */ + prepend(element: HTMLElement | undefined) { + dom.prependTo(element, this.element); + } + + /** + * Removes an element from this component. + * @param element + */ + removeChild(element: HTMLElement | undefined) { + dom.removeChildFrom(element, this.element); + } + + /** + * Wrapper method to add an event listener to an HTML element. + * + * @param obj + * The DOM element to add the event to. + * @param type + * The event name to add. + * @param func + * The callback function to be executed when the listener is triggered. + * @param persistent + * If this listener should persist beyond "destroy" commands. + */ + addEventListener(obj: any, type: string, func: any) { + if (!obj) { + return; + } + if ('addEventListener' in obj) { + obj.addEventListener(type, func, false); + } else if ('attachEvent' in obj) { + obj.attachEvent(`on${type}`, func); + } + this.attachedListeners.push({ obj, type, func }); + return this; + } + + /** + * Remove all the attached listeners. + */ + removeAttachedListeners() { + this.attachedListeners.forEach((item) => + this.removeEventListener(item.obj, item.type, item.func), + ); + this.attachedListeners = []; + } + + /** + * Remove an event listener from the object. + * + * @param obj + * @param type + */ + removeEventListener(obj: any, type: string, func: any) { + if (obj) { + obj.removeEventListener(type, func); + } + return this; + } + }; + }; } // Add the default component. diff --git a/src/experimental/base/component/__tests__/Component.test.ts b/src/experimental/base/component/__tests__/Component.test.ts index 07d9d679..8f5b24d4 100644 --- a/src/experimental/base/component/__tests__/Component.test.ts +++ b/src/experimental/base/component/__tests__/Component.test.ts @@ -2,76 +2,79 @@ import { Component as ComponentBase } from '../Component'; import { assert } from 'chai'; const Component = ComponentBase()(); -describe('Component', () => { - it('Should create a new Component component', () => { - // Default to an empty object. - const comp = new Component({ - type: 'textfield', - key: 'firstName' - }); - assert.equal(comp.options.language, 'en'); - assert.equal(comp.options.namespace, 'formio'); - assert.deepEqual(comp.component, { - type: 'textfield', - key: 'firstName', - protected: false, - persistent: true - }); +describe('Component', function () { + it('Should create a new Component component', function () { + // Default to an empty object. + const comp = new Component({ + type: 'textfield', + key: 'firstName', }); - - it('init hook should be called.', (done) => { - new Component({ - type: 'textfield', - key: 'lastName' - }, { - hooks: { - init: function() { - // Init method must be called. - assert(this instanceof Component, `'this' must be an instance of Component`); - done(); - } - } - }) + assert.equal(comp.options.language, 'en'); + assert.equal(comp.options.namespace, 'formio'); + assert.deepEqual(comp.component, { + type: 'textfield', + key: 'firstName', + protected: false, + persistent: true, }); + }); + + it('init hook should be called.', function (done) { + new Component( + { + type: 'textfield', + key: 'lastName', + }, + { + hooks: { + init: function () { + // Init method must be called. + assert(this instanceof Component, `'this' must be an instance of Component`); + done(); + }, + }, + }, + ); + }); - it('Should render a component', () => { - const parent = document.createElement('div'); - const element = document.createElement('div'); - parent.appendChild(element); - const comp = new Component({ - type: 'html', - key: 'html' - }); - comp.attach(element); + it('Should render a component', function () { + const parent = document.createElement('div'); + const element = document.createElement('div'); + parent.appendChild(element); + const comp = new Component({ + type: 'html', + key: 'html', }); + comp.attach(element); + }); - // xit ('Should validate a component', async () => { - // const comp = new Component({ - // type: 'textfield', - // key: 'firstName', - // validate: { - // required: true - // } - // }, { - // validator: Validator - // }); - // assert.equal(await comp.checkValidity(), false); - // comp.dataValue = 'testing'; - // assert.equal(await comp.checkValidity(), true); - // }); + // xit ('Should validate a component', async () => { + // const comp = new Component({ + // type: 'textfield', + // key: 'firstName', + // validate: { + // required: true + // } + // }, { + // validator: Validator + // }); + // assert.equal(await comp.checkValidity(), false); + // comp.dataValue = 'testing'; + // assert.equal(await comp.checkValidity(), true); + // }); - it ('Should clear attachedListeners array after detach', () => { - const element = document.createElement('div'); - const comp = new Component({ - type: 'textfield', - key: 'firstName' - }); - comp.attach(element); - assert.deepEqual(comp.attachedListeners, []); - const listenerObj = {obj: element, type: 'click', func: () => {}} - comp.attachedListeners.push(listenerObj); - assert.deepEqual(comp.attachedListeners, [listenerObj]); - comp.detach(); - assert.deepEqual(comp.attachedListeners, []); - }) + it('Should clear attachedListeners array after detach', function () { + const element = document.createElement('div'); + const comp = new Component({ + type: 'textfield', + key: 'firstName', + }); + comp.attach(element); + assert.deepEqual(comp.attachedListeners, []); + const listenerObj = { obj: element, type: 'click', func: () => {} }; + comp.attachedListeners.push(listenerObj); + assert.deepEqual(comp.attachedListeners, [listenerObj]); + comp.detach(); + assert.deepEqual(comp.attachedListeners, []); + }); }); diff --git a/src/experimental/base/data/DataComponent.ts b/src/experimental/base/data/DataComponent.ts index 07d8b314..850ceada 100644 --- a/src/experimental/base/data/DataComponent.ts +++ b/src/experimental/base/data/DataComponent.ts @@ -1,5 +1,5 @@ import { Components } from '../Components'; -import { NestedDataModel, ModelDecoratorInterface, ModelInterface } from '../../model'; +import { NestedDataModel, ModelDecoratorInterface, ModelInterface } from '../../model'; import { NestedComponent } from '../nested/NestedComponent'; /** @@ -16,16 +16,16 @@ import { NestedComponent } from '../nested/NestedComponent'; * } * } */ -export function DataComponent(props: any = {}) : ModelDecoratorInterface { - if (!props.type) { - props.type = 'data'; - } - if (!props.model) { - props.model = NestedDataModel; - } - return function(BaseClass?: ModelInterface) : ModelInterface { - return class ExtendedDataComponent extends NestedComponent(props)(BaseClass) {} - } +export function DataComponent(props: any = {}): ModelDecoratorInterface { + if (!props.type) { + props.type = 'data'; + } + if (!props.model) { + props.model = NestedDataModel; + } + return function (BaseClass?: ModelInterface): ModelInterface { + return class ExtendedDataComponent extends NestedComponent(props)(BaseClass) {}; + }; } Components.addDecorator(DataComponent, 'data'); diff --git a/src/experimental/base/data/__tests__/DataComponent.test.ts b/src/experimental/base/data/__tests__/DataComponent.test.ts index 5a40bd97..a2b8cf32 100644 --- a/src/experimental/base/data/__tests__/DataComponent.test.ts +++ b/src/experimental/base/data/__tests__/DataComponent.test.ts @@ -1,47 +1,49 @@ import { assert } from 'chai'; import { DataComponent as DataComponentBase } from '../DataComponent'; import { comp1 } from './fixtures'; -const DataComponent = DataComponentBase()() +const DataComponent = DataComponentBase()(); -describe('DataComponent', () => { - it ('Should create a new Data Component', () => { - const data = {}; - new DataComponent(comp1, {}, data); - assert.deepEqual(data, {employee: {}}); - }); +describe('DataComponent', function () { + it('Should create a new Data Component', function () { + const data = {}; + new DataComponent(comp1, {}, data); + assert.deepEqual(data, { employee: {} }); + }); - it ('Should initialize the data component with data', () => { - const data = { - employee: { - firstName: 'Joe', - lastName: 'Smith' - } - }; - const dataComp = new DataComponent(comp1, {}, data); - assert.deepEqual(dataComp.dataValue, { - firstName: 'Joe', - lastName: 'Smith' - }); - assert.equal(dataComp.components[0].dataValue, 'Joe'); - assert.equal(dataComp.components[1].dataValue, 'Smith'); + it('Should initialize the data component with data', function () { + const data = { + employee: { + firstName: 'Joe', + lastName: 'Smith', + }, + }; + const dataComp = new DataComponent(comp1, {}, data); + assert.deepEqual(dataComp.dataValue, { + firstName: 'Joe', + lastName: 'Smith', }); + assert.equal(dataComp.components[0].dataValue, 'Joe'); + assert.equal(dataComp.components[1].dataValue, 'Smith'); + }); - it ('Should set the value of the sub components', () => { - const data = {}; - const dataComp = new DataComponent(comp1, {}, data); - dataComp.dataValue = { - firstName: 'Joe', - lastName: 'Smith' - }; - assert.deepEqual(data, {employee: { - firstName: 'Joe', - lastName: 'Smith' - }}); - assert.deepEqual(dataComp.dataValue, { - firstName: 'Joe', - lastName: 'Smith' - }); - assert.equal(dataComp.components[0].dataValue, 'Joe'); - assert.equal(dataComp.components[1].dataValue, 'Smith'); + it('Should set the value of the sub components', function () { + const data = {}; + const dataComp = new DataComponent(comp1, {}, data); + dataComp.dataValue = { + firstName: 'Joe', + lastName: 'Smith', + }; + assert.deepEqual(data, { + employee: { + firstName: 'Joe', + lastName: 'Smith', + }, + }); + assert.deepEqual(dataComp.dataValue, { + firstName: 'Joe', + lastName: 'Smith', }); + assert.equal(dataComp.components[0].dataValue, 'Joe'); + assert.equal(dataComp.components[1].dataValue, 'Smith'); + }); }); diff --git a/src/experimental/base/data/__tests__/fixtures/comp1.ts b/src/experimental/base/data/__tests__/fixtures/comp1.ts index 04103b0f..6379725c 100644 --- a/src/experimental/base/data/__tests__/fixtures/comp1.ts +++ b/src/experimental/base/data/__tests__/fixtures/comp1.ts @@ -1,14 +1,14 @@ export default { - type: 'data', - key: 'employee', - components: [ - { - type: 'component', - key: 'firstName' - }, - { - type: 'component', - key: 'lastName' - } - ] -}; \ No newline at end of file + type: 'data', + key: 'employee', + components: [ + { + type: 'component', + key: 'firstName', + }, + { + type: 'component', + key: 'lastName', + }, + ], +}; diff --git a/src/experimental/base/data/__tests__/fixtures/index.ts b/src/experimental/base/data/__tests__/fixtures/index.ts index 2c5e7c7a..c00a1325 100644 --- a/src/experimental/base/data/__tests__/fixtures/index.ts +++ b/src/experimental/base/data/__tests__/fixtures/index.ts @@ -1,2 +1,2 @@ import comp1 from './comp1'; -export { comp1 }; \ No newline at end of file +export { comp1 }; diff --git a/src/experimental/base/nested/NestedComponent.ts b/src/experimental/base/nested/NestedComponent.ts index dd8418d4..2daf246a 100644 --- a/src/experimental/base/nested/NestedComponent.ts +++ b/src/experimental/base/nested/NestedComponent.ts @@ -1,59 +1,59 @@ import { Components } from '../Components'; import { ComponentSchema, Component } from '../component/Component'; -import { NestedModel, ModelDecoratorInterface, ModelInterface } from '../../model'; +import { NestedModel, ModelDecoratorInterface, ModelInterface } from '../../model'; export interface NestedComponentSchema extends ComponentSchema { - components: Array; + components: Array; } -export function NestedComponent(props: any = {}) : ModelDecoratorInterface { - if (!props.type) { - props.type = 'nested'; - } - if (!props.model) { - props.model = NestedModel; - } - if (!props.factory) { - props.factory = Components; - } - return function(BaseClass?: ModelInterface) : ModelInterface { - return class ExtendedNestedComponent extends Component(props)(BaseClass) { - public get defaultTemplate(): any { - return (ctx: any) => `
${ctx.instance.renderComponents()}
`; - } +export function NestedComponent(props: any = {}): ModelDecoratorInterface { + if (!props.type) { + props.type = 'nested'; + } + if (!props.model) { + props.model = NestedModel; + } + if (!props.factory) { + props.factory = Components; + } + return function (BaseClass?: ModelInterface): ModelInterface { + return class ExtendedNestedComponent extends Component(props)(BaseClass) { + public get defaultTemplate(): any { + return (ctx: any) => `
${ctx.instance.renderComponents()}
`; + } - /** - * Attach a html element to this nestd component. - * @param element - */ - public async attach(element: HTMLElement) { - await super.attach(element); - if (this.element) { - const promises: any = []; - const children = this.element.querySelectorAll(`[data-within="${this.id}"]`); - Array.prototype.slice.call(children).forEach((child: HTMLElement, index: any) => { - promises.push(this.components[index].attach(child)); - }); - await Promise.all(promises); - } - return this; - } + /** + * Attach a html element to this nestd component. + * @param element + */ + public async attach(element: HTMLElement) { + await super.attach(element); + if (this.element) { + const promises: any = []; + const children = this.element.querySelectorAll(`[data-within="${this.id}"]`); + Array.prototype.slice.call(children).forEach((child: HTMLElement, index: any) => { + promises.push(this.components[index].attach(child)); + }); + await Promise.all(promises); + } + return this; + } - /** - * Detach components. - */ - detach() { - super.detach(); - this.eachComponent((comp: any) => comp.detach()); - } + /** + * Detach components. + */ + detach() { + super.detach(); + this.eachComponent((comp: any) => comp.detach()); + } - renderComponents() { - return this.components.reduce((tpl: string, comp: any) => { - return tpl + comp.render().replace(/(<[^\>]+)/, `$1 data-within="${this.id}"`); - }, ''); - } - } + renderComponents() { + return this.components.reduce((tpl: string, comp: any) => { + return tpl + comp.render().replace(/(<[^>]+)/, `$1 data-within="${this.id}"`); + }, ''); + } }; + }; } Components.addDecorator(NestedComponent, 'nested'); diff --git a/src/experimental/base/nested/__tests__/NestedComponent.test.ts b/src/experimental/base/nested/__tests__/NestedComponent.test.ts index 712585be..4b1b05b6 100644 --- a/src/experimental/base/nested/__tests__/NestedComponent.test.ts +++ b/src/experimental/base/nested/__tests__/NestedComponent.test.ts @@ -3,31 +3,34 @@ import { assert } from 'chai'; import { comp1, comp2 } from './fixtures'; const NestedComponent = NestedBase()(); -describe('Nested', () => { - it('Should render a nested component', () => { - const nested = new NestedComponent(comp1); - assert.equal(nested.render(), `
` + - `Hello` + - `

There

` + - `
`); - }); +describe('Nested', function () { + it('Should render a nested component', function () { + const nested = new NestedComponent(comp1); + assert.equal( + nested.render(), + `
` + + `Hello` + + `

There

` + + `
`, + ); + }); - it ('Should not set or get data', () => { - const data = {}; - const nested = new NestedComponent(comp2, {}, data); - nested.dataValue = { - firstName: 'Joe', - lastName: 'Smith' - }; - assert.deepEqual(data, { - firstName: 'Joe', - lastName: 'Smith' - }); - assert.deepEqual(nested.dataValue, { - firstName: 'Joe', - lastName: 'Smith' - }); - assert.equal(nested.components[0].dataValue, 'Joe'); - assert.equal(nested.components[1].dataValue, 'Smith'); + it('Should not set or get data', function () { + const data = {}; + const nested = new NestedComponent(comp2, {}, data); + nested.dataValue = { + firstName: 'Joe', + lastName: 'Smith', + }; + assert.deepEqual(data, { + firstName: 'Joe', + lastName: 'Smith', + }); + assert.deepEqual(nested.dataValue, { + firstName: 'Joe', + lastName: 'Smith', }); + assert.equal(nested.components[0].dataValue, 'Joe'); + assert.equal(nested.components[1].dataValue, 'Smith'); + }); }); diff --git a/src/experimental/base/nested/__tests__/fixtures/comp1.ts b/src/experimental/base/nested/__tests__/fixtures/comp1.ts index e5bf0169..6b31acd1 100644 --- a/src/experimental/base/nested/__tests__/fixtures/comp1.ts +++ b/src/experimental/base/nested/__tests__/fixtures/comp1.ts @@ -1,18 +1,18 @@ export default { - type: 'nested', - key: 'nested', - components: [ - { - type: 'html', - key: 'html1', - content: 'Hello', - tag: 'strong' - }, - { - type: 'html', - key: 'html2', - content: 'There', - tag: 'h2' - }, - ] -}; \ No newline at end of file + type: 'nested', + key: 'nested', + components: [ + { + type: 'html', + key: 'html1', + content: 'Hello', + tag: 'strong', + }, + { + type: 'html', + key: 'html2', + content: 'There', + tag: 'h2', + }, + ], +}; diff --git a/src/experimental/base/nested/__tests__/fixtures/comp2.ts b/src/experimental/base/nested/__tests__/fixtures/comp2.ts index 04103b0f..6379725c 100644 --- a/src/experimental/base/nested/__tests__/fixtures/comp2.ts +++ b/src/experimental/base/nested/__tests__/fixtures/comp2.ts @@ -1,14 +1,14 @@ export default { - type: 'data', - key: 'employee', - components: [ - { - type: 'component', - key: 'firstName' - }, - { - type: 'component', - key: 'lastName' - } - ] -}; \ No newline at end of file + type: 'data', + key: 'employee', + components: [ + { + type: 'component', + key: 'firstName', + }, + { + type: 'component', + key: 'lastName', + }, + ], +}; diff --git a/src/experimental/base/nested/__tests__/fixtures/index.ts b/src/experimental/base/nested/__tests__/fixtures/index.ts index bdd99755..7c38dd80 100644 --- a/src/experimental/base/nested/__tests__/fixtures/index.ts +++ b/src/experimental/base/nested/__tests__/fixtures/index.ts @@ -1,3 +1,3 @@ import comp1 from './comp1'; import comp2 from './comp2'; -export { comp1, comp2 }; \ No newline at end of file +export { comp1, comp2 }; diff --git a/src/experimental/components/__tests__/datatable.test.ts b/src/experimental/components/__tests__/datatable.test.ts index 80e218ef..ed65fca3 100644 --- a/src/experimental/components/__tests__/datatable.test.ts +++ b/src/experimental/components/__tests__/datatable.test.ts @@ -1,37 +1,44 @@ import { assert } from 'chai'; import { DataTableComponent } from '../test'; -describe('DataTable', () => { - it ('Should create a DataTable component', () => { - const trimHtml = (html: string) => { - return html.replace(/\n/g, "") - .replace(/[\t ]+\[\t ]+\<") - .replace(/\>[\t ]+$/g, ">"); - } - const dataTable = new DataTableComponent({ - type: 'datatable', - key: 'customers', - components: [ - { - type: 'datavalue', - key: 'firstName', - label: 'First Name' - }, - { - type: 'datavalue', - key: 'lastName', - label: 'Last Name' - } - ] - }, {}, { - customers: [ - {firstName: 'Joe', lastName: 'Smith'}, - {firstName: 'Sally', lastName: 'Thompson'}, - {firstName: 'Mary', lastName: 'Bono'} - ] - }); - assert.equal(trimHtml(dataTable.render()), trimHtml(` +describe('DataTable', function () { + it('Should create a DataTable component', function () { + const trimHtml = (html: string) => { + return html + .replace(/\n/g, '') + .replace(/[\t ]+[\t ]+<') + .replace(/>[\t ]+$/g, '>'); + }; + const dataTable = new DataTableComponent( + { + type: 'datatable', + key: 'customers', + components: [ + { + type: 'datavalue', + key: 'firstName', + label: 'First Name', + }, + { + type: 'datavalue', + key: 'lastName', + label: 'Last Name', + }, + ], + }, + {}, + { + customers: [ + { firstName: 'Joe', lastName: 'Smith' }, + { firstName: 'Sally', lastName: 'Thompson' }, + { firstName: 'Mary', lastName: 'Bono' }, + ], + }, + ); + assert.equal( + trimHtml(dataTable.render()), + trimHtml(` @@ -53,6 +60,7 @@ describe('DataTable', () => { -
Bono
`)); - }); -}); \ No newline at end of file + `), + ); + }); +}); diff --git a/src/experimental/components/__tests__/datavalue.test.ts b/src/experimental/components/__tests__/datavalue.test.ts index ffb703ff..51531070 100644 --- a/src/experimental/components/__tests__/datavalue.test.ts +++ b/src/experimental/components/__tests__/datavalue.test.ts @@ -1,15 +1,19 @@ import { assert } from 'chai'; import { DataValueComponent } from '../test'; -describe('DataValue', () => { - it ('Should create a DataValue component', () => { - const dataValue = new DataValueComponent({ - type: 'datavalue', - key: 'firstName', - label: 'First Name' - }, {}, { - firstName: 'Joe' - }); - assert.equal((dataValue as any).render(), 'Joe'); - }); -}); \ No newline at end of file +describe('DataValue', function () { + it('Should create a DataValue component', function () { + const dataValue = new DataValueComponent( + { + type: 'datavalue', + key: 'firstName', + label: 'First Name', + }, + {}, + { + firstName: 'Joe', + }, + ); + assert.equal((dataValue as any).render(), 'Joe'); + }); +}); diff --git a/src/experimental/components/__tests__/fixtures/comp1.ts b/src/experimental/components/__tests__/fixtures/comp1.ts index 263f2cf2..184b8755 100644 --- a/src/experimental/components/__tests__/fixtures/comp1.ts +++ b/src/experimental/components/__tests__/fixtures/comp1.ts @@ -1,16 +1,16 @@ export default { - type: 'htmlcontainer', - tag: 'div', - className: 'testing', - attrs: [ - {attr: 'one', value: 'two'}, - {attr: 'three', value: 'four'} - ], - components: [ - { - type: 'html', - tag: 'span', - content: 'Testing' - } - ] -}; \ No newline at end of file + type: 'htmlcontainer', + tag: 'div', + className: 'testing', + attrs: [ + { attr: 'one', value: 'two' }, + { attr: 'three', value: 'four' }, + ], + components: [ + { + type: 'html', + tag: 'span', + content: 'Testing', + }, + ], +}; diff --git a/src/experimental/components/__tests__/fixtures/comp2.ts b/src/experimental/components/__tests__/fixtures/comp2.ts index a5741400..a6f4412f 100644 --- a/src/experimental/components/__tests__/fixtures/comp2.ts +++ b/src/experimental/components/__tests__/fixtures/comp2.ts @@ -1,27 +1,27 @@ export default { - type: 'htmlcontainer', - tag: 'div', - className: 'testing', - attrs: [ - {attr: 'one', value: 'two'}, - {attr: 'three', value: 'four'} - ], - components: [ + type: 'htmlcontainer', + tag: 'div', + className: 'testing', + attrs: [ + { attr: 'one', value: 'two' }, + { attr: 'three', value: 'four' }, + ], + components: [ + { + type: 'html', + tag: 'span', + content: 'Testing', + }, + { + type: 'htmlcontainer', + tag: 'div', + components: [ { - type: 'html', - tag: 'span', - content: 'Testing' + type: 'html', + tag: 'h3', + content: 'This is a title', }, - { - type: 'htmlcontainer', - tag: 'div', - components: [ - { - type: 'html', - tag: 'h3', - content: 'This is a title' - } - ] - } - ] -}; \ No newline at end of file + ], + }, + ], +}; diff --git a/src/experimental/components/__tests__/fixtures/index.ts b/src/experimental/components/__tests__/fixtures/index.ts index bdd99755..7c38dd80 100644 --- a/src/experimental/components/__tests__/fixtures/index.ts +++ b/src/experimental/components/__tests__/fixtures/index.ts @@ -1,3 +1,3 @@ import comp1 from './comp1'; import comp2 from './comp2'; -export { comp1, comp2 }; \ No newline at end of file +export { comp1, comp2 }; diff --git a/src/experimental/components/__tests__/html.test.ts b/src/experimental/components/__tests__/html.test.ts index 545a2117..439619cf 100644 --- a/src/experimental/components/__tests__/html.test.ts +++ b/src/experimental/components/__tests__/html.test.ts @@ -1,32 +1,38 @@ import { assert } from 'chai'; import { HTMLComponent } from '../test'; -describe('HTML Component', () => { - it ('Should create an HTML Component', () => { - const comp = new HTMLComponent({ - type: 'html', - tag: 'span', - className: 'testing', - content: 'Testing', - attrs: [ - {attr: 'one', value: 'two'}, - {attr: 'three', value: 'four'} - ] - }); - assert.equal(comp.render(), 'Testing'); +describe('HTML Component', function () { + it('Should create an HTML Component', function () { + const comp = new HTMLComponent({ + type: 'html', + tag: 'span', + className: 'testing', + content: 'Testing', + attrs: [ + { attr: 'one', value: 'two' }, + { attr: 'three', value: 'four' }, + ], }); + assert.equal( + comp.render(), + 'Testing', + ); + }); - it ('Should also allow for key-value pair attributes', () => { - const comp = new HTMLComponent({ - type: 'html', - tag: 'span', - className: 'testing', - content: 'Testing', - attrs: { - one: 'two', - three: 'four' - } - }); - assert.equal(comp.render(), 'Testing'); + it('Should also allow for key-value pair attributes', function () { + const comp = new HTMLComponent({ + type: 'html', + tag: 'span', + className: 'testing', + content: 'Testing', + attrs: { + one: 'two', + three: 'four', + }, }); -}); \ No newline at end of file + assert.equal( + comp.render(), + 'Testing', + ); + }); +}); diff --git a/src/experimental/components/__tests__/htmlcontainer.test.ts b/src/experimental/components/__tests__/htmlcontainer.test.ts index c83d99c2..3334c2ff 100644 --- a/src/experimental/components/__tests__/htmlcontainer.test.ts +++ b/src/experimental/components/__tests__/htmlcontainer.test.ts @@ -2,35 +2,44 @@ import { assert } from 'chai'; import { HTMLContainerComponent } from '../test'; import { comp1, comp2 } from './fixtures'; -describe('HTMLContainerComponent', () => { - it ('Should create an HTMLContainerComponent', () => { - const comp = new HTMLContainerComponent(comp1); - assert.equal(comp.render(), '
' + - `Testing` + - '
'); - }); +describe('HTMLContainerComponent', function () { + it('Should create an HTMLContainerComponent', function () { + const comp = new HTMLContainerComponent(comp1); + assert.equal( + comp.render(), + '
' + + `Testing` + + '
', + ); + }); - it ('Should create nested HTML hiararchies', () => { - const comp = new HTMLContainerComponent(comp2); - assert.equal(comp.render(), '
' + - `Testing` + - `
` + - `

This is a title

` + - '
' + - '
'); - }); + it('Should create nested HTML hiararchies', function () { + const comp = new HTMLContainerComponent(comp2); + assert.equal( + comp.render(), + '
' + + `Testing` + + `
` + + `

This is a title

` + + '
' + + '
', + ); + }); - it ('Should sanitize the output to ensure XSS does not occur.', () => { - const comp = new HTMLContainerComponent(comp2); - const parentElement = document.createElement('div'); - const element = document.createElement('div'); - parentElement.appendChild(element); - comp.attach(element); - assert.equal(parentElement.innerHTML, '
' + - `Testing` + - `
` + - `

This is a title

` + - '
' + - '
'); - }); + it('Should sanitize the output to ensure XSS does not occur.', function () { + const comp = new HTMLContainerComponent(comp2); + const parentElement = document.createElement('div'); + const element = document.createElement('div'); + parentElement.appendChild(element); + comp.attach(element); + assert.equal( + parentElement.innerHTML, + '
' + + `Testing` + + `
` + + `

This is a title

` + + '
' + + '
', + ); + }); }); diff --git a/src/experimental/components/datatable.ts b/src/experimental/components/datatable.ts index eca3429c..b7509a9c 100644 --- a/src/experimental/components/datatable.ts +++ b/src/experimental/components/datatable.ts @@ -4,40 +4,47 @@ import { ArrayComponent } from '../base'; * A base class for a data table. */ export class DataTable { - [x: string]: any; - constructor(public component?: any, public options?: any, public data?: any) {} - renderClasses() { - let classes = ''; - if (this.component.bordered) { - classes += ' table-bordered'; - } - if (this.component.striped) { - classes += ' table-striped'; - } - if (this.component.hover) { - classes += ' table-hover'; - } - if (this.component.condensed) { - classes += ' table-condensed'; - } - return classes; + [x: string]: any; + constructor( + public component?: any, + public options?: any, + public data?: any, + ) {} + renderClasses() { + let classes = ''; + if (this.component.bordered) { + classes += ' table-bordered'; } - - renderContext(extend: any = {}): any { - return Object.assign({ - classes: this.renderClasses() - }, extend); + if (this.component.striped) { + classes += ' table-striped'; + } + if (this.component.hover) { + classes += ' table-hover'; } + if (this.component.condensed) { + classes += ' table-condensed'; + } + return classes; + } + + renderContext(extend: any = {}): any { + return Object.assign( + { + classes: this.renderClasses(), + }, + extend, + ); + } } @ArrayComponent({ - type: 'datatable', - schema: { - bordered: true, - striped: false, - hover: true, - condensed: true - }, - template: 'datatable', + type: 'datatable', + schema: { + bordered: true, + striped: false, + hover: true, + condensed: true, + }, + template: 'datatable', }) export class DataTableComponent extends DataTable {} diff --git a/src/experimental/components/datavalue.ts b/src/experimental/components/datavalue.ts index 9e25dbb6..4f8b15e8 100644 --- a/src/experimental/components/datavalue.ts +++ b/src/experimental/components/datavalue.ts @@ -2,14 +2,14 @@ import { Component } from '../base'; import { HTML } from './html'; @Component({ - type: 'datavalue', - schema: { - tag: 'span', - attrs: [], - className: '' - }, - template: (ctx: any) => { - return `<${ctx.tag} ref="val"${ctx.attrs}>${ctx.value()}`; - } + type: 'datavalue', + schema: { + tag: 'span', + attrs: [], + className: '', + }, + template: (ctx: any) => { + return `<${ctx.tag} ref="val"${ctx.attrs}>${ctx.value()}`; + }, }) export class DataValueComponent extends HTML {} diff --git a/src/experimental/components/html.ts b/src/experimental/components/html.ts index b40eb4ee..ff89aa28 100644 --- a/src/experimental/components/html.ts +++ b/src/experimental/components/html.ts @@ -1,53 +1,62 @@ import { Component } from '../base'; export const HTMLProperties = { - type: 'html', - schema: { - tag: 'span', - content: '', - attrs: [], - className: '' - }, - template: (ctx: any) => { - return `<${ctx.tag} ref="${ctx.ref}"${ctx.attrs}>${ctx.t(ctx.content)}`; - } + type: 'html', + schema: { + tag: 'span', + content: '', + attrs: [], + className: '', + }, + template: (ctx: any) => { + return `<${ctx.tag} ref="${ctx.ref}"${ctx.attrs}>${ctx.t(ctx.content)}`; + }, }; /** * Base class for HTML based components. */ export class HTML { - [x: string]: any; - constructor(public component?: any, public options?: any, public data?: any) {} - public getAttributes() { - let hasClass = false; - let attrs = ''; - for (let i in this.component.attrs) { - if (this.component.attrs.hasOwnProperty(i)) { - const attrValue = this.component.attrs[i]; - const isString = Number.isNaN(parseInt(i)); - let attr = isString ? i : attrValue.attr; - const value = isString ? attrValue : attrValue.value; - if (attr === 'class' && this.component.className) { - hasClass = true; - attr += ` ${this.component.className}`; - } - attrs += ` ${attr}="${this.interpolate(value, this.evalContext())}"`; - } - } - if (!hasClass && this.component.className) { - attrs += ` class="${this.interpolate(this.component.className, this.evalContext())}"`; + [x: string]: any; + constructor( + public component?: any, + public options?: any, + public data?: any, + ) {} + public getAttributes() { + let hasClass = false; + let attrs = ''; + for (const i in this.component.attrs) { + if (this.component.attrs.hasOwnProperty(i)) { + const attrValue = this.component.attrs[i]; + const isString = Number.isNaN(parseInt(i)); + let attr = isString ? i : attrValue.attr; + const value = isString ? attrValue : attrValue.value; + if (attr === 'class' && this.component.className) { + hasClass = true; + attr += ` ${this.component.className}`; } - return attrs; + attrs += ` ${attr}="${this.interpolate(value, this.evalContext())}"`; + } } - - public renderContext(extend: any = {}): any { - return Object.assign({ - tag: this.component.tag, - ref: this.component.type, - content: this.component.content ? this.interpolate(this.component.content, this.evalContext()) : '', - attrs: this.getAttributes() - }, extend); + if (!hasClass && this.component.className) { + attrs += ` class="${this.interpolate(this.component.className, this.evalContext())}"`; } + return attrs; + } + + public renderContext(extend: any = {}): any { + return Object.assign( + { + tag: this.component.tag, + ref: this.component.type, + content: this.component.content + ? this.interpolate(this.component.content, this.evalContext()) + : '', + attrs: this.getAttributes(), + }, + extend, + ); + } } @Component(HTMLProperties) diff --git a/src/experimental/components/htmlcontainer.ts b/src/experimental/components/htmlcontainer.ts index 6ddd7551..2d65c2e3 100644 --- a/src/experimental/components/htmlcontainer.ts +++ b/src/experimental/components/htmlcontainer.ts @@ -5,16 +5,21 @@ import { HTML, HTMLProperties } from './html'; * Base HTMLContainer component. */ export class HTMLContainer extends HTML { - renderContext(extend: any = {}) { - return super.renderContext(Object.assign({ - content: this.renderComponents() - }, extend)); - } + renderContext(extend: any = {}) { + return super.renderContext( + Object.assign( + { + content: this.renderComponents(), + }, + extend, + ), + ); + } } @NestedComponent({ - type: 'htmlcontainer', - schema: HTMLProperties.schema, - template: HTMLProperties.template + type: 'htmlcontainer', + schema: HTMLProperties.schema, + template: HTMLProperties.template, }) export class HTMLContainerComponent extends HTMLContainer {} diff --git a/src/experimental/components/index.ts b/src/experimental/components/index.ts index 75ede5a9..2f31e5ad 100644 --- a/src/experimental/components/index.ts +++ b/src/experimental/components/index.ts @@ -10,12 +10,12 @@ export { DataTable, DataTableComponent } from './datatable'; export { DataValueComponent } from './datavalue'; export { Input, InputComponent } from './input/input'; export default { - components: { - html: HTMLComponent, - htmlcontainer: HTMLContainerComponent, - datatable: DataTableComponent, - datavalue: DataValueComponent, - input: InputComponent - }, - templates + components: { + html: HTMLComponent, + htmlcontainer: HTMLContainerComponent, + datatable: DataTableComponent, + datavalue: DataValueComponent, + input: InputComponent, + }, + templates, }; diff --git a/src/experimental/components/input/__tests__/fixtures/comp1.ts b/src/experimental/components/input/__tests__/fixtures/comp1.ts index cd7ef072..a0c08d7c 100644 --- a/src/experimental/components/input/__tests__/fixtures/comp1.ts +++ b/src/experimental/components/input/__tests__/fixtures/comp1.ts @@ -1,8 +1,8 @@ export default { - type: 'input', - key: 'firstName', - attrs: { - one: 'two', - three: 'four' - } -}; \ No newline at end of file + type: 'input', + key: 'firstName', + attrs: { + one: 'two', + three: 'four', + }, +}; diff --git a/src/experimental/components/input/__tests__/fixtures/comp2.ts b/src/experimental/components/input/__tests__/fixtures/comp2.ts index 19440077..fbfab8a1 100644 --- a/src/experimental/components/input/__tests__/fixtures/comp2.ts +++ b/src/experimental/components/input/__tests__/fixtures/comp2.ts @@ -1,39 +1,39 @@ export default { - type: 'htmlcontainer', - components: [ - { - type: 'html', - tag: 'label', - content: 'First Name', - attrs: { - class: 'form-label', - for: 'input-firstname' - } - }, - { - type: 'input', - key: 'firstName', - attrs: { - class: 'form-control', - placeholder: 'Enter your first name' - } - }, - { - type: 'html', - tag: 'label', - content: 'Last Name', - attrs: { - class: 'form-label', - for: 'input-firstname' - } - }, - { - type: 'input', - key: 'lastName', - attrs: { - class: 'form-control', - placeholder: 'Enter your last name' - } - } - ] -}; \ No newline at end of file + type: 'htmlcontainer', + components: [ + { + type: 'html', + tag: 'label', + content: 'First Name', + attrs: { + class: 'form-label', + for: 'input-firstname', + }, + }, + { + type: 'input', + key: 'firstName', + attrs: { + class: 'form-control', + placeholder: 'Enter your first name', + }, + }, + { + type: 'html', + tag: 'label', + content: 'Last Name', + attrs: { + class: 'form-label', + for: 'input-firstname', + }, + }, + { + type: 'input', + key: 'lastName', + attrs: { + class: 'form-control', + placeholder: 'Enter your last name', + }, + }, + ], +}; diff --git a/src/experimental/components/input/__tests__/fixtures/index.ts b/src/experimental/components/input/__tests__/fixtures/index.ts index bdd99755..7c38dd80 100644 --- a/src/experimental/components/input/__tests__/fixtures/index.ts +++ b/src/experimental/components/input/__tests__/fixtures/index.ts @@ -1,3 +1,3 @@ import comp1 from './comp1'; import comp2 from './comp2'; -export { comp1, comp2 }; \ No newline at end of file +export { comp1, comp2 }; diff --git a/src/experimental/components/input/__tests__/input.test.ts b/src/experimental/components/input/__tests__/input.test.ts index 0a69ff4b..43438785 100644 --- a/src/experimental/components/input/__tests__/input.test.ts +++ b/src/experimental/components/input/__tests__/input.test.ts @@ -2,59 +2,67 @@ import { assert } from 'chai'; import { InputComponent, HTMLContainerComponent } from '../../test'; import { comp1, comp2 } from './fixtures'; -describe('Input Component', () => { - it('Should create a new input component', () => { - const comp = new InputComponent(comp1); - assert.equal(comp.render(), ``); - }); +describe('Input Component', function () { + it('Should create a new input component', function () { + const comp = new InputComponent(comp1); + assert.equal( + comp.render(), + ``, + ); + }); - it('Should create input of different types', () => { - const comp = new InputComponent({...comp1, inputType: 'number'}); - assert.equal(comp.render(), ``); - }); + it('Should create input of different types', function () { + const comp = new InputComponent({ ...comp1, inputType: 'number' }); + assert.equal( + comp.render(), + ``, + ); + }); - it('Should render a Form input with label and input', async () => { - const comp = new HTMLContainerComponent(comp2); - const parentElement = document.createElement('div'); - const element = document.createElement('div'); - parentElement.appendChild(element); - await comp.attach(element); - comp.setValue({ - firstName: 'Joe', - lastName: 'Smith' - }); - assert.equal(parentElement.innerHTML, '' + - `` + - `` + - `` + - `` + - ''); - assert.deepEqual(comp.dataValue, { - firstName: 'Joe', - lastName: 'Smith' - }); + it('Should render a Form input with label and input', async function () { + const comp = new HTMLContainerComponent(comp2); + const parentElement = document.createElement('div'); + const element = document.createElement('div'); + parentElement.appendChild(element); + await comp.attach(element); + comp.setValue({ + firstName: 'Joe', + lastName: 'Smith', + }); + assert.equal( + parentElement.innerHTML, + '' + + `` + + `` + + `` + + `` + + '', + ); + assert.deepEqual(comp.dataValue, { + firstName: 'Joe', + lastName: 'Smith', + }); - await new Promise((resolve: any, reject: any) => { - comp.on('change', () => { - // Verify the data changed as well. - try { - assert.deepEqual(comp.dataValue, { - firstName: 'Sally', - lastName: 'Smith' - }); - } - catch (err) { - return reject(err); - } - resolve(); - }); + await new Promise((resolve: any, reject: any) => { + comp.on('change', () => { + // Verify the data changed as well. + try { + assert.deepEqual(comp.dataValue, { + firstName: 'Sally', + lastName: 'Smith', + }); + } catch (err) { + return reject(err); + } + resolve(); + }); - // Trigger an input change. - const firstName: any = comp.components[1].element; - firstName.value = 'Sally'; - const evt = document.createEvent("Events"); - evt.initEvent("input", true, true); - firstName.dispatchEvent(evt); - }); + // Trigger an input change. + const firstName: any = comp.components[1].element; + firstName.value = 'Sally'; + const evt = document.createEvent('Events'); + evt.initEvent('input', true, true); + firstName.dispatchEvent(evt); }); + }); }); diff --git a/src/experimental/components/input/input.ts b/src/experimental/components/input/input.ts index 9b98872e..2cfed489 100644 --- a/src/experimental/components/input/input.ts +++ b/src/experimental/components/input/input.ts @@ -5,40 +5,42 @@ import { HTML, HTMLProperties } from '../html'; * Base Input component for extending purposes. */ export class Input extends HTML { - public element: any; - getAttributes() { - const attributes = super.getAttributes(); - const inputName = `${this.component.type}-${this.component.key}`.toLowerCase().replace(/[^a-z0-9\-]+/g, '_'); - return ` type="${(this as any).component.inputType}" id="${inputName}" name="${inputName}"${attributes}`; - } - onInput() { - this.updateValue(this.element.value); - } - async attach(element: HTMLElement) { - this.addEventListener(this.element, this.component.changeEvent, this.onInput.bind(this)); - return this; - } - detach() { - this.removeEventListener(this.element, this.component.changeEvent, this.onInput.bind(this)); - } - setValue(value: any) { - if (this.element) { - this.element.value = value; - } + public element: any; + getAttributes() { + const attributes = super.getAttributes(); + const inputName = `${this.component.type}-${this.component.key}` + .toLowerCase() + .replace(/[^a-z0-9-]+/g, '_'); + return ` type="${(this as any).component.inputType}" id="${inputName}" name="${inputName}"${attributes}`; + } + onInput() { + this.updateValue(this.element.value); + } + async attach() { + this.addEventListener(this.element, this.component.changeEvent, this.onInput.bind(this)); + return this; + } + detach() { + this.removeEventListener(this.element, this.component.changeEvent, this.onInput.bind(this)); + } + setValue(value: any) { + if (this.element) { + this.element.value = value; } + } } @Component({ - type: 'input', - template: HTMLProperties.template, - schema: { - ...HTMLProperties.schema, - ...{ - tag: 'input', - ref: 'input', - changeEvent: 'input', - inputType: 'text' - } - } + type: 'input', + template: HTMLProperties.template, + schema: { + ...HTMLProperties.schema, + ...{ + tag: 'input', + ref: 'input', + changeEvent: 'input', + inputType: 'text', + }, + }, }) export class InputComponent extends Input {} diff --git a/src/experimental/components/templates/bootstrap/datatable/index.ts b/src/experimental/components/templates/bootstrap/datatable/index.ts index 8940330a..c85df311 100644 --- a/src/experimental/components/templates/bootstrap/datatable/index.ts +++ b/src/experimental/components/templates/bootstrap/datatable/index.ts @@ -1,2 +1,2 @@ const html = require('./html.ejs.js').default; -export { html }; \ No newline at end of file +export { html }; diff --git a/src/experimental/components/templates/bootstrap/index.ts b/src/experimental/components/templates/bootstrap/index.ts index 8797880d..08afd973 100644 --- a/src/experimental/components/templates/bootstrap/index.ts +++ b/src/experimental/components/templates/bootstrap/index.ts @@ -1 +1 @@ -export * as datatable from './datatable'; \ No newline at end of file +export * as datatable from './datatable'; diff --git a/src/experimental/components/templates/index.ts b/src/experimental/components/templates/index.ts index bc83c3eb..7a3fd75b 100644 --- a/src/experimental/components/templates/index.ts +++ b/src/experimental/components/templates/index.ts @@ -1,2 +1,2 @@ import * as bootstrap from './bootstrap'; -export default { bootstrap } \ No newline at end of file +export default { bootstrap }; diff --git a/src/experimental/components/test.ts b/src/experimental/components/test.ts index 6beca3c3..1cc80b02 100644 --- a/src/experimental/components/test.ts +++ b/src/experimental/components/test.ts @@ -1,10 +1,10 @@ import { Components } from '../base'; import { Template } from '../template'; import module from './index'; -for (let name in module.components) { - if (module.components.hasOwnProperty(name)) { - Components.addComponent((module as any).components[name], name); - } +for (const name in module.components) { + if (module.components.hasOwnProperty(name)) { + Components.addComponent((module as any).components[name], name); + } } import templates from './templates'; Template.addTemplates(templates); diff --git a/src/experimental/core.ts b/src/experimental/core.ts index 9f851f26..9141c199 100644 --- a/src/experimental/core.ts +++ b/src/experimental/core.ts @@ -8,91 +8,90 @@ import components from './components'; import modules from '../modules'; export default class FormioCore extends Formio { - static Components = Components; - static render = render; - static Evaluator = Evaluator; - static Utils = Utils; - static Templates = Template; - static usePlugin(key: string, plugin: any) { - switch (key) { - case 'options': - if (!(Formio as any).options) { - return; - } - (Formio as any).options = merge((Formio as any).options, plugin); - break; - case 'templates': - if (!(Formio as any).Templates) { - return; - } - const current = (Formio as any).Templates.framework || 'bootstrap'; - for (const framework of Object.keys(plugin)) { - (Formio as any).Templates.extendTemplate(framework, plugin[framework]); - } - if (plugin[current]) { - (Formio as any).Templates.current = plugin[current]; - } - break; - case 'components': - if (!(Formio as any).Components) { - return; - } - (Formio as any).Components.setComponents(plugin); - break; - case 'framework': - if (!(Formio as any).Templates) { - return; - } - (Formio as any).Templates.framework = plugin; - break; - case 'fetch': - for (const name of Object.keys(plugin)) { - Formio.registerPlugin(plugin[name], name); - } - break; - case 'rules': - if (!(Formio as any).Rules) { - return; - } - (Formio as any).Rules.addRules(plugin); - break; - case 'evaluator': - if (!(Formio as any).Evaluator) { - return; - } - (Formio as any).Evaluator.registerEvaluator(plugin); - break; - default: - console.log('Unknown plugin option', key); + static Components = Components; + static render = render; + static Evaluator = Evaluator; + static Utils = Utils; + static Templates = Template; + static usePlugin(key: string, plugin: any) { + switch (key) { + case 'options': + if (!(Formio as any).options) { + return; } - } - - static useModule(module: any) { - // Sanity check. - if (typeof module !== 'object') { - return; + (Formio as any).options = merge((Formio as any).options, plugin); + break; + case 'templates': + if (!(Formio as any).Templates) { + return; + } + const current = (Formio as any).Templates.framework || 'bootstrap'; + for (const framework of Object.keys(plugin)) { + (Formio as any).Templates.extendTemplate(framework, plugin[framework]); + } + if (plugin[current]) { + (Formio as any).Templates.current = plugin[current]; + } + break; + case 'components': + if (!(Formio as any).Components) { + return; } - for (const key of Object.keys(module)) { - FormioCore.usePlugin(key, module[key]); + (Formio as any).Components.setComponents(plugin); + break; + case 'framework': + if (!(Formio as any).Templates) { + return; } + (Formio as any).Templates.framework = plugin; + break; + case 'fetch': + for (const name of Object.keys(plugin)) { + Formio.registerPlugin(plugin[name], name); + } + break; + case 'rules': + if (!(Formio as any).Rules) { + return; + } + (Formio as any).Rules.addRules(plugin); + break; + case 'evaluator': + if (!(Formio as any).Evaluator) { + return; + } + (Formio as any).Evaluator.registerEvaluator(plugin); + break; + default: + console.log('Unknown plugin option', key); } + } - /** - * Allows passing in plugins as multiple arguments or an array of plugins. - * - * Formio.plugins(plugin1, plugin2, etc); - * Formio.plugins([plugin1, plugin2, etc]); - */ - static use(...mods: any) { - mods.forEach((mod: any) => { - if (Array.isArray(mod)) { - mod.forEach(p => FormioCore.useModule(p)); - } - else { - FormioCore.useModule(mod); - } - }); + static useModule(module: any) { + // Sanity check. + if (typeof module !== 'object') { + return; } + for (const key of Object.keys(module)) { + FormioCore.usePlugin(key, module[key]); + } + } + + /** + * Allows passing in plugins as multiple arguments or an array of plugins. + * + * Formio.plugins(plugin1, plugin2, etc); + * Formio.plugins([plugin1, plugin2, etc]); + */ + static use(...mods: any) { + mods.forEach((mod: any) => { + if (Array.isArray(mod)) { + mod.forEach((p) => FormioCore.useModule(p)); + } else { + FormioCore.useModule(mod); + } + }); + } } FormioCore.use(components); diff --git a/src/experimental/index.ts b/src/experimental/index.ts index ab6d228d..245db3f2 100644 --- a/src/experimental/index.ts +++ b/src/experimental/index.ts @@ -4,4 +4,4 @@ export * from './model'; export * from './components'; export * from './template'; export { FormioCore as Formio }; -export default FormioCore; \ No newline at end of file +export default FormioCore; diff --git a/src/experimental/model/EventEmitter.ts b/src/experimental/model/EventEmitter.ts index ddac6963..d4e5cb6e 100644 --- a/src/experimental/model/EventEmitter.ts +++ b/src/experimental/model/EventEmitter.ts @@ -1,82 +1,82 @@ export interface ModelInterface { - component?: any; - options?: any; - data?: any; - new (component?: any, options?: any, data?: any): any; + component?: any; + options?: any; + data?: any; + new (component?: any, options?: any, data?: any): any; } import EventEmitterBase from 'eventemitter3'; -export function EventEmitter(BaseClass?: any) : ModelInterface { - if (!BaseClass) { - BaseClass = class _BaseClass {}; - } - return class EventEmitter extends BaseClass { - /** - * The parent entity. - */ - public parent: any = null; +export function EventEmitter(BaseClass?: any): ModelInterface { + if (!BaseClass) { + BaseClass = class _BaseClass {}; + } + return class EventEmitter extends BaseClass { + /** + * The parent entity. + */ + public parent: any = null; - /** - * The events to fire for this model. - */ - public events: EventEmitterBase = new EventEmitterBase(); + /** + * The events to fire for this model. + */ + public events: EventEmitterBase = new EventEmitterBase(); - /** - * Bubble an event up to the parent. - * - * @param event - * @param args - * @returns - */ - public bubble(event: any, ...args: any) { - if (this.parent) { - return this.parent.bubble(event, ...args); - } - return this.emit(event, ...args); - } + /** + * Bubble an event up to the parent. + * + * @param event + * @param args + * @returns + */ + public bubble(event: any, ...args: any) { + if (this.parent) { + return this.parent.bubble(event, ...args); + } + return this.emit(event, ...args); + } - /** - * Emit an event on this component. - * @param event - * @param args - * @returns - */ - public emit(event: any, ...args: any) { - return this.events.emit(event, ...args); - } + /** + * Emit an event on this component. + * @param event + * @param args + * @returns + */ + public emit(event: any, ...args: any) { + return this.events.emit(event, ...args); + } - /** - * Register an event subscriber. - * @param event - * @param fn - * @param args - * @returns - */ - public on(event: any, fn: any, ...args: any) { - return this.events.on(event, fn, ...args); - } + /** + * Register an event subscriber. + * @param event + * @param fn + * @param args + * @returns + */ + public on(event: any, fn: any, ...args: any) { + return this.events.on(event, fn, ...args); + } - /** - * Register an event subscriber that will only be called once. - * @param event - * @param fn - * @param args - * @returns - */ - public once(event: any, fn: any, ...args: any) { - return this.events.once(event, fn, ...args); - } + /** + * Register an event subscriber that will only be called once. + * @param event + * @param fn + * @param args + * @returns + */ + public once(event: any, fn: any, ...args: any) { + return this.events.once(event, fn, ...args); + } - /** - * Turn off the event registrations. - * @param event - * @param args - * @returns - */ - public off(event: any, ...args: any) { - return this.events.off(event, ...args); - } + /** + * Turn off the event registrations. + * @param event + * @param args + * @returns + */ + public off(event: any, ...args: any) { + return this.events.off(event, ...args); } + }; } -export { EventEmitterBase }; \ No newline at end of file +export { EventEmitterBase }; diff --git a/src/experimental/model/Model.ts b/src/experimental/model/Model.ts index b80d0020..e6a28434 100644 --- a/src/experimental/model/Model.ts +++ b/src/experimental/model/Model.ts @@ -3,166 +3,166 @@ import { EventEmitter, ModelInterface } from './EventEmitter'; export { ModelInterface }; export interface ModelDecoratorInterface { - (BaseClass?: ModelInterface) : ModelInterface; + (BaseClass?: ModelInterface): ModelInterface; } -export function Model(props: any = {}) : ModelDecoratorInterface { - if (!props.schema) { - props.schema = {}; - } - if (!props.schema.key) { - props.schema.key = ''; - } - return function(BaseClass?: ModelInterface) : ModelInterface { - return class BaseModel extends EventEmitter(BaseClass) { - /** - * A random generated ID for this entity. - */ - public id!: string; - - /** - * The root entity. - */ - public root: any = null; - - /** - * The default JSON schema - * @param extend - */ - public static schema(): any { - return props.schema; - } - - /** - * @constructor - * @param component - * @param options - * @param data - */ - constructor(public component: any = {}, public options: any = {}, public data: any = {}) { - super(component, options, data); - this.id = `e${Math.random().toString(36).substring(7)}`; - this.component = merge({}, this.defaultSchema, this.component) as any; - this.options = {...this.defaultOptions, ...this.options}; - if (!this.options.noInit) { - this.init(); - } - } - - public get defaultOptions(): any { - return {}; - } - - public get defaultSchema(): any { - return BaseModel.schema(); - } - - /** - * Initializes the entity. - */ - public init() { - this.hook('init'); - } - - /** - * Return the errors from validation for this component. - */ - public get errors() { - return this.validator.errors; - } - - /** - * The empty value for this component. - * - * @return {null} - */ - get emptyValue(): any { - return null; - } - - - /** - * Checks to see if this components value is empty. - * - * @param value - * @returns - */ - isEmpty(value = this.dataValue) { - const isEmptyArray = (isArray(value) && value.length === 1) ? isEqual(value[0], this.emptyValue) : false; - return value == null || value.length === 0 || isEqual(value, this.emptyValue) || isEmptyArray; - } - - /** - * Returns the data value for this component. - */ - public get dataValue(): any { - return this.component.key ? get(this.data, this.component.key) : this.data; - } - - /** - * Sets the datavalue for this component. - */ - public set dataValue(value: any) { - if (this.component.key) { - set(this.data, this.component.key, value); - } - } - - /** - * Determine if this component has changed values. - * - * @param value - The value to compare against the current value. - */ - public hasChanged(value: any) { - return String(value) !== String(this.dataValue); - } - - /** - * Updates the data model value - * @param value The value to update within this component. - * @return boolean true if the value has changed. - */ - public updateValue(value: any): boolean { - const changed = this.hasChanged(value); - this.dataValue = value; - if (changed) { - // Bubble a change event. - this.bubble('change', value); - } - return changed; - } - - /** - * Get the model value. - * @returns - */ - public getValue(): any { - return this.dataValue; - } - - /** - * Allow for options to hook into the functionality of this entity. - * @return {*} - */ - hook(name: string, ...args: any) { - if ( - this.options && - this.options.hooks && - this.options.hooks[name] - ) { - return this.options.hooks[name].apply(this, args); - } - else { - // If this is an async hook instead of a sync. - const fn = (typeof args[args.length - 1] === 'function') ? args[args.length - 1] : null; - if (fn) { - return fn(null, args[1]); - } - else { - return args[1]; - } - } - } - }; +export function Model(props: any = {}): ModelDecoratorInterface { + if (!props.schema) { + props.schema = {}; + } + if (!props.schema.key) { + props.schema.key = ''; + } + return function (BaseClass?: ModelInterface): ModelInterface { + return class BaseModel extends EventEmitter(BaseClass) { + /** + * A random generated ID for this entity. + */ + public id!: string; + + /** + * The root entity. + */ + public root: any = null; + + /** + * The default JSON schema + * @param extend + */ + public static schema(): any { + return props.schema; + } + + /** + * @constructor + * @param component + * @param options + * @param data + */ + constructor( + public component: any = {}, + public options: any = {}, + public data: any = {}, + ) { + super(component, options, data); + this.id = `e${Math.random().toString(36).substring(7)}`; + this.component = merge({}, this.defaultSchema, this.component) as any; + this.options = { ...this.defaultOptions, ...this.options }; + if (!this.options.noInit) { + this.init(); + } + } + + public get defaultOptions(): any { + return {}; + } + + public get defaultSchema(): any { + return BaseModel.schema(); + } + + /** + * Initializes the entity. + */ + public init() { + this.hook('init'); + } + + /** + * Return the errors from validation for this component. + */ + public get errors() { + return this.validator.errors; + } + + /** + * The empty value for this component. + * + * @return {null} + */ + get emptyValue(): any { + return null; + } + + /** + * Checks to see if this components value is empty. + * + * @param value + * @returns + */ + isEmpty(value = this.dataValue) { + const isEmptyArray = + isArray(value) && value.length === 1 ? isEqual(value[0], this.emptyValue) : false; + return ( + value == null || value.length === 0 || isEqual(value, this.emptyValue) || isEmptyArray + ); + } + + /** + * Returns the data value for this component. + */ + public get dataValue(): any { + return this.component.key ? get(this.data, this.component.key) : this.data; + } + + /** + * Sets the datavalue for this component. + */ + public set dataValue(value: any) { + if (this.component.key) { + set(this.data, this.component.key, value); + } + } + + /** + * Determine if this component has changed values. + * + * @param value - The value to compare against the current value. + */ + public hasChanged(value: any) { + return String(value) !== String(this.dataValue); + } + + /** + * Updates the data model value + * @param value The value to update within this component. + * @return boolean true if the value has changed. + */ + public updateValue(value: any): boolean { + const changed = this.hasChanged(value); + this.dataValue = value; + if (changed) { + // Bubble a change event. + this.bubble('change', value); + } + return changed; + } + + /** + * Get the model value. + * @returns + */ + public getValue(): any { + return this.dataValue; + } + + /** + * Allow for options to hook into the functionality of this entity. + * @return {*} + */ + hook(name: string, ...args: any) { + if (this.options && this.options.hooks && this.options.hooks[name]) { + return this.options.hooks[name].apply(this, args); + } else { + // If this is an async hook instead of a sync. + const fn = typeof args[args.length - 1] === 'function' ? args[args.length - 1] : null; + if (fn) { + return fn(null, args[1]); + } else { + return args[1]; + } + } + } }; + }; } diff --git a/src/experimental/model/NestedArrayModel.ts b/src/experimental/model/NestedArrayModel.ts index cac582d3..559187ed 100644 --- a/src/experimental/model/NestedArrayModel.ts +++ b/src/experimental/model/NestedArrayModel.ts @@ -1,195 +1,195 @@ import { get } from 'lodash'; import { ModelInterface, ModelDecoratorInterface } from './Model'; import { NestedDataModel } from './NestedDataModel'; -export function NestedArrayModel(props: any = {}) : ModelDecoratorInterface { - return function(BaseClass?: ModelInterface) : ModelInterface { - return class BaseNestedArrayModel extends NestedDataModel(props)(BaseClass) { - /** - * The rows for this component. Each row contains new instances of components. - */ - public rows!: Array>; - get defaultValue() { - return []; - } +export function NestedArrayModel(props: any = {}): ModelDecoratorInterface { + return function (BaseClass?: ModelInterface): ModelInterface { + return class BaseNestedArrayModel extends NestedDataModel(props)(BaseClass) { + /** + * The rows for this component. Each row contains new instances of components. + */ + public rows!: Array>; + get defaultValue() { + return []; + } - /** - * Returns a row of componments at the provided index. - * @param index The index of the row to return - */ - row(index: number): Array { - return (index < this.rows.length) ? this.rows[index] : []; - } + /** + * Returns a row of componments at the provided index. + * @param index The index of the row to return + */ + row(index: number): Array { + return index < this.rows.length ? this.rows[index] : []; + } - /** - * Removes a row and detatches all components within that row. - * - * @param index The index of the row to remove. - */ - removeRow(index: number) { - this.row(index).forEach((comp: any) => this.removeComponent(comp)); - this.dataValue.splice(index, 1); - this.rows.splice(index, 1); - } - - /** - * Adds a new row of components. - * - * @param data The data context to pass to this row of components. - */ - addRow(data: any = {}, index: number = 0) { - const rowData = data; - this.dataValue[index] = rowData; - this.createRowComponents(rowData, index); - } + /** + * Removes a row and detatches all components within that row. + * + * @param index The index of the row to remove. + */ + removeRow(index: number) { + this.row(index).forEach((comp: any) => this.removeComponent(comp)); + this.dataValue.splice(index, 1); + this.rows.splice(index, 1); + } - /** - * Sets the data for a specific row of components. - * @param rowData The data to set - * @param index The index of the rows to set the data within. - */ - setRowData(rowData: any, index: number) { - this.dataValue[index] = rowData; - this.row(index)?.forEach((comp: any) => (comp.data = rowData)); - } + /** + * Adds a new row of components. + * + * @param data The data context to pass to this row of components. + */ + addRow(data: any = {}, index: number = 0) { + const rowData = data; + this.dataValue[index] = rowData; + this.createRowComponents(rowData, index); + } - /** - * Determines if the data within a row has changed. - * - * @param rowData - * @param index - */ - rowChanged(rowData: any, index: number): boolean { - let changed = false; - this.row(index)?.forEach((comp: any) => { - const hasChanged: boolean = comp.hasChanged(get(rowData, comp.component.key)); - changed = hasChanged || changed; - if (hasChanged) { - comp.bubble('change', comp); - } - }); - return changed; - } + /** + * Sets the data for a specific row of components. + * @param rowData The data to set + * @param index The index of the rows to set the data within. + */ + setRowData(rowData: any, index: number) { + this.dataValue[index] = rowData; + this.row(index)?.forEach((comp: any) => (comp.data = rowData)); + } - /** - * Creates all components for each row. - * @param data - * @returns - */ - createComponents(data: any): Array { - this.rows = []; - let added: Array = []; - this.eachRowValue(data, (row: any, index: number) => { - added = added.concat(this.createRowComponents(row, index)); - }); - return added; - } + /** + * Determines if the data within a row has changed. + * + * @param rowData + * @param index + */ + rowChanged(rowData: any, index: number): boolean { + let changed = false; + this.row(index)?.forEach((comp: any) => { + const hasChanged: boolean = comp.hasChanged(get(rowData, comp.component.key)); + changed = hasChanged || changed; + if (hasChanged) { + comp.bubble('change', comp); + } + }); + return changed; + } - /** - * Creates a new row of components. - * - * @param data The data context to pass along to this row of components. - */ - createRowComponents(data: any, index: number = 0): Array { - const comps = super.createComponents(data, (comp: any) => { - comp.rowIndex = index; - }); - this.rows[index] = comps; - return comps; - } + /** + * Creates all components for each row. + * @param data + * @returns + */ + createComponents(data: any): Array { + this.rows = []; + let added: Array = []; + this.eachRowValue(data, (row: any, index: number) => { + added = added.concat(this.createRowComponents(row, index)); + }); + return added; + } - getIndexes(value: Array) { - if (super.getIndexes) { - return super.getIndexes(value); - } - return { - min: 0, - max: (value.length - 1) - }; - } + /** + * Creates a new row of components. + * + * @param data The data context to pass along to this row of components. + */ + createRowComponents(data: any, index: number = 0): Array { + const comps = super.createComponents(data, (comp: any) => { + comp.rowIndex = index; + }); + this.rows[index] = comps; + return comps; + } - eachRowValue(value: any, fn: any) { - if (!value || !value.length) { - return; - } - const indexes = this.getIndexes(value); - for (let i = indexes.min; i <= indexes.max; i++) { - fn(value[i], i); - } - } + getIndexes(value: Array) { + if (super.getIndexes) { + return super.getIndexes(value); + } + return { + min: 0, + max: value.length - 1, + }; + } - /** - * The empty value for this component. - * - * @return {array} - */ - get emptyValue(): any { - return []; - } + eachRowValue(value: any, fn: any) { + if (!value || !value.length) { + return; + } + const indexes = this.getIndexes(value); + for (let i = indexes.min; i <= indexes.max; i++) { + fn(value[i], i); + } + } - /** - * Returns the dataValue for this component. - */ - public get dataValue() { - return this.component.key ? get(this.data, this.component.key) : this.data; - } + /** + * The empty value for this component. + * + * @return {array} + */ + get emptyValue(): any { + return []; + } - /** - * Set the datavalue of an array component. - * - * @param value The value to set this component to. - */ - public set dataValue(value: any) { - // Only set the value if it is an array. - if (Array.isArray(value)) { - // Get the current data value. - const dataValue = this.dataValue; - this.eachRowValue(value, (row: any, index: number) => { - if (index >= dataValue.length) { - this.addRow(row, index); - } - this.setRowData(row, index) - }); + /** + * Returns the dataValue for this component. + */ + public get dataValue() { + return this.component.key ? get(this.data, this.component.key) : this.data; + } - // Remove superfluous rows. - if (dataValue.length > value.length) { - for (let i = dataValue.length - 1; i >= value.length; i--) { - this.removeRow(i); - } - } - } + /** + * Set the datavalue of an array component. + * + * @param value The value to set this component to. + */ + public set dataValue(value: any) { + // Only set the value if it is an array. + if (Array.isArray(value)) { + // Get the current data value. + const dataValue = this.dataValue; + this.eachRowValue(value, (row: any, index: number) => { + if (index >= dataValue.length) { + this.addRow(row, index); } + this.setRowData(row, index); + }); - /** - * Determine if this array component has changed. - * - * @param value - */ - public hasChanged(value: any): boolean { - const dataValue = this.dataValue; - // If the length changes, then this compnent has changed. - if (value.length !== dataValue.length) { - this.emit('changed', this); - return true; - } - let changed = false; - this.eachRowValue(value, (rowData: any, index: number) => { - changed = this.rowChanged(rowData, index) || changed; - }); - return changed; + // Remove superfluous rows. + if (dataValue.length > value.length) { + for (let i = dataValue.length - 1; i >= value.length; i--) { + this.removeRow(i); } + } + } + } - /** - * Sets the value of an array component. - * - * @param value - */ - public setValue(value: any): boolean { - var changed = false; - this.eachComponentValue(value, (comp: any, val: any) => { - changed = comp.setValue(val) || changed; - }); - return changed; - } + /** + * Determine if this array component has changed. + * + * @param value + */ + public hasChanged(value: any): boolean { + const dataValue = this.dataValue; + // If the length changes, then this compnent has changed. + if (value.length !== dataValue.length) { + this.emit('changed', this); + return true; } - } -}; + let changed = false; + this.eachRowValue(value, (rowData: any, index: number) => { + changed = this.rowChanged(rowData, index) || changed; + }); + return changed; + } + + /** + * Sets the value of an array component. + * + * @param value + */ + public setValue(value: any): boolean { + let changed = false; + this.eachComponentValue(value, (comp: any, val: any) => { + changed = comp.setValue(val) || changed; + }); + return changed; + } + }; + }; +} diff --git a/src/experimental/model/NestedDataModel.ts b/src/experimental/model/NestedDataModel.ts index 1563f07c..6a596fb6 100644 --- a/src/experimental/model/NestedDataModel.ts +++ b/src/experimental/model/NestedDataModel.ts @@ -1,37 +1,37 @@ import { get, set } from 'lodash'; import { ModelInterface, ModelDecoratorInterface } from './Model'; import { NestedModel } from './NestedModel'; -export function NestedDataModel(props: any = {}) : ModelDecoratorInterface { - return function(BaseClass?: ModelInterface) : ModelInterface { - return class BaseNestedDataModel extends NestedModel(props)(BaseClass) { - get emptyValue(): any { - return {}; - } - get defaultValue() { - return {}; - } +export function NestedDataModel(props: any = {}): ModelDecoratorInterface { + return function (BaseClass?: ModelInterface): ModelInterface { + return class BaseNestedDataModel extends NestedModel(props)(BaseClass) { + get emptyValue(): any { + return {}; + } + get defaultValue() { + return {}; + } - /** - * Get the component data. - */ - componentData() { - if (!this.component.key) { - return this.data; - } - const compData: any = get(this.data, this.component.key, this.defaultValue); - if (!Object.keys(compData).length) { - set(this.data, this.component.key, compData); - } - return compData; - } + /** + * Get the component data. + */ + componentData() { + if (!this.component.key) { + return this.data; + } + const compData: any = get(this.data, this.component.key, this.defaultValue); + if (!Object.keys(compData).length) { + set(this.data, this.component.key, compData); + } + return compData; + } - public get dataValue() { - return this.component.key ? get(this.data, this.component.key) : this.data; - } + public get dataValue() { + return this.component.key ? get(this.data, this.component.key) : this.data; + } - public set dataValue(value: any) { - this.eachComponentValue(value, (comp: any, val: any) => (comp.dataValue = val)); - } - } + public set dataValue(value: any) { + this.eachComponentValue(value, (comp: any, val: any) => (comp.dataValue = val)); + } }; -}; \ No newline at end of file + }; +} diff --git a/src/experimental/model/NestedModel.ts b/src/experimental/model/NestedModel.ts index bd63e0cf..fef1dbb8 100644 --- a/src/experimental/model/NestedModel.ts +++ b/src/experimental/model/NestedModel.ts @@ -1,169 +1,173 @@ import { each, get } from 'lodash'; import { Model, ModelInterface, ModelDecoratorInterface } from './Model'; -export function NestedModel(props: any = {}) : ModelDecoratorInterface { - if (!props.schema) { - props.schema = {}; - } - if (!props.schema.components) { - props.schema.components = []; - } - return function(BaseClass?: ModelInterface) : ModelInterface { - return class BaseNestedModel extends Model(props)(BaseClass) { - public components!: Array; +export function NestedModel(props: any = {}): ModelDecoratorInterface { + if (!props.schema) { + props.schema = {}; + } + if (!props.schema.components) { + props.schema.components = []; + } + return function (BaseClass?: ModelInterface): ModelInterface { + return class BaseNestedModel extends Model(props)(BaseClass) { + public components!: Array; - /** - * Initialize the nested entity by creating the children. - */ - init() { - super.init(); - this.components = []; - this.createComponents(this.componentData()); - } + /** + * Initialize the nested entity by creating the children. + */ + init() { + super.init(); + this.components = []; + this.createComponents(this.componentData()); + } - /** - * Get the component data. - * @returns - */ - componentData() { - return this.data; - } + /** + * Get the component data. + * @returns + */ + componentData() { + return this.data; + } - /** - * Creates a new component entity. - * @param component - * @param options - * @param data - * @returns - */ - createComponent(component: any, options: any, data: any) { - if (!props.factory) { - console.log('Cannot create components. No "factory" provided.'); - return null; - } - const comp = props.factory.create(component, { - noInit: true, - ...options - }, data); - comp.parent = this; - comp.root = this.root || this; - comp.init(); - return comp; - } + /** + * Creates a new component entity. + * @param component + * @param options + * @param data + * @returns + */ + createComponent(component: any, options: any, data: any) { + if (!props.factory) { + console.log('Cannot create components. No "factory" provided.'); + return null; + } + const comp = props.factory.create( + component, + { + noInit: true, + ...options, + }, + data, + ); + comp.parent = this; + comp.root = this.root || this; + comp.init(); + return comp; + } - /** - * Creates the components. - * @param data - * @returns - */ - createComponents(data: any, eachComp?: any): Array { - const added: Array = []; - (this.component.components || []).forEach((comp: any) => { - const newComp = this.createComponent(comp, this.options, data); - if (newComp) { - this.components.push(newComp); - added.push(newComp); - if (eachComp) { - eachComp(newComp); - } - } - }); - return added; + /** + * Creates the components. + * @param data + * @returns + */ + createComponents(data: any, eachComp?: any): Array { + const added: Array = []; + (this.component.components || []).forEach((comp: any) => { + const newComp = this.createComponent(comp, this.options, data); + if (newComp) { + this.components.push(newComp); + added.push(newComp); + if (eachComp) { + eachComp(newComp); } + } + }); + return added; + } - /** - * Removes a child comopnent. - * @param component - */ - removeComponent(component: any) { - (this.components || []).forEach((comp: any, index: number) => { - if (comp === component) { - if (comp.detach) { - comp.detach(); - } - this.components.splice(index, 1); - } - }); + /** + * Removes a child comopnent. + * @param component + */ + removeComponent(component: any) { + (this.components || []).forEach((comp: any, index: number) => { + if (comp === component) { + if (comp.detach) { + comp.detach(); } + this.components.splice(index, 1); + } + }); + } - /** - * Checks for the validity of this component and all components within this component. - * @returns - */ - public async checkValidity() { - return this.components.reduce((valid: boolean, comp: any) => { - return valid && comp.checkValidity(); - }, this.checkComponentValidity()); - } + /** + * Checks for the validity of this component and all components within this component. + * @returns + */ + public async checkValidity() { + return this.components.reduce((valid: boolean, comp: any) => { + return valid && comp.checkValidity(); + }, this.checkComponentValidity()); + } - /** - * Get the default value for this nested entity. - */ - get defaultValue() { - return {}; - } + /** + * Get the default value for this nested entity. + */ + get defaultValue() { + return {}; + } - /** - * The empty value for this component. - * - * @return {null} - */ - get emptyValue(): any { - return {}; - } + /** + * The empty value for this component. + * + * @return {null} + */ + get emptyValue(): any { + return {}; + } - /** - * Get the datavalue of this component. - */ - public get dataValue() { - return this.data; - } + /** + * Get the datavalue of this component. + */ + public get dataValue() { + return this.data; + } - /** - * Perform an iteration over each component within this container component. - * - * @param {function} fn - Called for each component - */ - eachComponent(fn: Function) { - each(this.components, (component: any, index: any) => { - if (fn(component, index) === false) { - return false; - } - }); - } + /** + * Perform an iteration over each component within this container component. + * + * @param {function} fn - Called for each component + */ + eachComponent(fn: Function) { + each(this.components, (component: any, index: any) => { + if (fn(component, index) === false) { + return false; + } + }); + } - /** - * Iterate through each component value. - * - * @param value The context data value. - * @param fn Callback to be called with the component and the value for that component. - */ - public eachComponentValue(value: any, fn: any) { - if (Object.keys(value).length) { - this.eachComponent((comp: any) => { - fn(comp, get(value, comp.component.key)); - }); - } - } + /** + * Iterate through each component value. + * + * @param value The context data value. + * @param fn Callback to be called with the component and the value for that component. + */ + public eachComponentValue(value: any, fn: any) { + if (Object.keys(value).length) { + this.eachComponent((comp: any) => { + fn(comp, get(value, comp.component.key)); + }); + } + } - /** - * Set the data value for this nested entity. - */ - public set dataValue(value: any) { - this.eachComponentValue(value, (comp: any, val: any) => (comp.dataValue = val)); - } + /** + * Set the data value for this nested entity. + */ + public set dataValue(value: any) { + this.eachComponentValue(value, (comp: any, val: any) => (comp.dataValue = val)); + } - /** - * Sets the value for a data component. - * - * @param value - */ - public setValue(value: any): boolean { - var changed = false; - this.eachComponentValue(value, (comp: any, val: any) => { - changed = comp.setValue(val) || changed; - }); - return changed; - } - } + /** + * Sets the value for a data component. + * + * @param value + */ + public setValue(value: any): boolean { + let changed = false; + this.eachComponentValue(value, (comp: any, val: any) => { + changed = comp.setValue(val) || changed; + }); + return changed; + } }; -}; + }; +} diff --git a/src/experimental/model/__tests__/Model.test.ts b/src/experimental/model/__tests__/Model.test.ts index ff90598a..2b3d17bc 100644 --- a/src/experimental/model/__tests__/Model.test.ts +++ b/src/experimental/model/__tests__/Model.test.ts @@ -1,37 +1,45 @@ import { assert } from 'chai'; import { Model } from '../Model'; const BaseModel = Model()(); -describe('Model', () => { - it('new Model()', () => { - const model = new BaseModel({ - key: 'firstName' - }, {}, { - firstName: 'Joe' - }); - assert.equal(model.dataValue, 'Joe'); - model.dataValue = 'Sally'; - assert.equal(model.dataValue, 'Sally'); - assert.deepEqual(model.data, {firstName: 'Sally'}); - }); +describe('Model', function () { + it('new Model()', function () { + const model = new BaseModel( + { + key: 'firstName', + }, + {}, + { + firstName: 'Joe', + }, + ); + assert.equal(model.dataValue, 'Joe'); + model.dataValue = 'Sally'; + assert.equal(model.dataValue, 'Sally'); + assert.deepEqual(model.data, { firstName: 'Sally' }); + }); - it('Model.isEmpty', () => { - const model = new BaseModel({ - key: 'firstName' - }, {}, { - firstName: 'Joe' - }); - assert.equal(model.isEmpty(), false); - model.dataValue = ''; - assert.equal(model.isEmpty(), true); - model.dataValue = null; - assert.equal(model.isEmpty(), true); - model.dataValue = []; - assert.equal(model.isEmpty(), true); - model.dataValue = [null]; - assert.equal(model.isEmpty(), true); - model.dataValue = ['']; - assert.equal(model.isEmpty(), false); - model.dataValue = ['hello']; - assert.equal(model.isEmpty(), false); - }); + it('Model.isEmpty', function () { + const model = new BaseModel( + { + key: 'firstName', + }, + {}, + { + firstName: 'Joe', + }, + ); + assert.equal(model.isEmpty(), false); + model.dataValue = ''; + assert.equal(model.isEmpty(), true); + model.dataValue = null; + assert.equal(model.isEmpty(), true); + model.dataValue = []; + assert.equal(model.isEmpty(), true); + model.dataValue = [null]; + assert.equal(model.isEmpty(), true); + model.dataValue = ['']; + assert.equal(model.isEmpty(), false); + model.dataValue = ['hello']; + assert.equal(model.isEmpty(), false); + }); }); diff --git a/src/experimental/model/index.ts b/src/experimental/model/index.ts index 2e66dd95..eb39a81a 100644 --- a/src/experimental/model/index.ts +++ b/src/experimental/model/index.ts @@ -2,4 +2,4 @@ export { EventEmitter } from './EventEmitter'; export { Model, ModelDecoratorInterface, ModelInterface } from './Model'; export { NestedModel } from './NestedModel'; export { NestedDataModel } from './NestedDataModel'; -export { NestedArrayModel } from './NestedArrayModel'; \ No newline at end of file +export { NestedArrayModel } from './NestedArrayModel'; diff --git a/src/experimental/template/Template.ts b/src/experimental/template/Template.ts index 2974b21f..acd7617d 100644 --- a/src/experimental/template/Template.ts +++ b/src/experimental/template/Template.ts @@ -4,102 +4,102 @@ import { merge } from 'lodash'; * Manages all the available templates which can be rendered. */ export class Template { - public static templates: any = {}; - public static _current: any = {}; - public static _framework: string = 'bootstrap'; + public static templates: any = {}; + public static _current: any = {}; + public static _framework: string = 'bootstrap'; - /** - * Adds a collection of template frameworks to the renderer. - * @param templates - */ - public static addTemplates(templates: any) { - var framework = Template.framework; - Template.templates = merge(Template.templates, templates); - Template.framework = framework; - } + /** + * Adds a collection of template frameworks to the renderer. + * @param templates + */ + public static addTemplates(templates: any) { + const framework = Template.framework; + Template.templates = merge(Template.templates, templates); + Template.framework = framework; + } - /** - * Adds some templates to the existing template. - * @param name - * @param template - */ - public static addTemplate(name: string, template: any) { - Template.templates[name] = merge(Template.current, template); - if (Template.templates.hasOwnProperty(Template._framework)) { - Template._current = Template.templates[Template._framework]; - } + /** + * Adds some templates to the existing template. + * @param name + * @param template + */ + public static addTemplate(name: string, template: any) { + Template.templates[name] = merge(Template.current, template); + if (Template.templates.hasOwnProperty(Template._framework)) { + Template._current = Template.templates[Template._framework]; } + } - /** - * Extend an existing template. - * @param name - * @param template - */ - public static extendTemplate(name: string, template: any) { - Template.templates[name] = merge(Template.templates[name], template); - if (Template.templates.hasOwnProperty(Template._framework)) { - Template._current = Template.templates[Template._framework]; - } + /** + * Extend an existing template. + * @param name + * @param template + */ + public static extendTemplate(name: string, template: any) { + Template.templates[name] = merge(Template.templates[name], template); + if (Template.templates.hasOwnProperty(Template._framework)) { + Template._current = Template.templates[Template._framework]; } + } - /** - * Sets a template. - * @param name - * @param template - */ - public static setTemplate(name: string, template: any) { - Template.addTemplate(name, template); - } + /** + * Sets a template. + * @param name + * @param template + */ + public static setTemplate(name: string, template: any) { + Template.addTemplate(name, template); + } - /** - * Set the current template. - */ - public static set current(templates) { - const defaultTemplates = Template.current; - Template._current = merge(defaultTemplates, templates); - } + /** + * Set the current template. + */ + public static set current(templates) { + const defaultTemplates = Template.current; + Template._current = merge(defaultTemplates, templates); + } - /** - * Get the current template. - */ - public static get current() { - return Template._current; - } + /** + * Get the current template. + */ + public static get current() { + return Template._current; + } - /** - * Sets the current framework. - */ - public static set framework(framework) { - Template._framework = framework; - if (Template.templates.hasOwnProperty(framework)) { - Template._current = Template.templates[framework]; - } + /** + * Sets the current framework. + */ + public static set framework(framework) { + Template._framework = framework; + if (Template.templates.hasOwnProperty(framework)) { + Template._current = Template.templates[framework]; } + } - /** - * Gets the current framework. - */ - public static get framework() { - return Template._framework; - } + /** + * Gets the current framework. + */ + public static get framework() { + return Template._framework; + } - /** - * Render a partial within the current template. - * @param name - * @param ctx - * @param mode - * @returns - */ - public static render(name: any, ctx: any, mode: string = 'html', defaultTemplate: any = null) { - if (typeof name === 'function') { - return name(ctx); - } - if (this.current[name] && this.current[name][mode]) { - return this.current[name][mode](ctx); - } - if (defaultTemplate) { - return defaultTemplate(ctx); - } - return 'Unknown template'; + /** + * Render a partial within the current template. + * @param name + * @param ctx + * @param mode + * @returns + */ + public static render(name: any, ctx: any, mode: string = 'html', defaultTemplate: any = null) { + if (typeof name === 'function') { + return name(ctx); + } + if (this.current[name] && this.current[name][mode]) { + return this.current[name][mode](ctx); + } + if (defaultTemplate) { + return defaultTemplate(ctx); } -} \ No newline at end of file + return 'Unknown template'; + } +} diff --git a/src/modules/index.ts b/src/modules/index.ts index 29b6ccce..8de16338 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -1,4 +1,2 @@ import { JSONLogicModule } from './jsonlogic'; -export default [ - JSONLogicModule -]; \ No newline at end of file +export default [JSONLogicModule]; diff --git a/src/modules/jsonlogic/__tests__/operators.test.ts b/src/modules/jsonlogic/__tests__/operators.test.ts index 61e10846..b454f21e 100644 --- a/src/modules/jsonlogic/__tests__/operators.test.ts +++ b/src/modules/jsonlogic/__tests__/operators.test.ts @@ -1,123 +1,135 @@ import { expect } from 'chai'; import { jsonLogic } from '../jsonLogic'; -describe('Lodash operators', () => { - describe('Arrays', () => { +describe('Lodash operators', function () { + describe('Arrays', function () {}); - }); - describe('Collection', () => { + describe('Collection', function () {}); - }); - describe('Date', () => { + describe('Date', function () {}); - }); - describe('Function', () => { + describe('Function', function () {}); - }); - describe('Lang', () => { - it('isEqual', () => { - const logicTrue = { _isEqual: [[2, 3], [2, 3]] }; - const logicFalse = { _isEqual: [[2, 3], [2, 4]] }; + describe('Lang', function () { + it('isEqual', function () { + const logicTrue = { + _isEqual: [ + [2, 3], + [2, 3], + ], + }; + const logicFalse = { + _isEqual: [ + [2, 3], + [2, 4], + ], + }; expect(jsonLogic.apply(logicTrue)).to.be.equal(true); expect(jsonLogic.apply(logicFalse)).to.be.equal(false); }); }); - describe('Math', () => { - it('add', () => { + + describe('Math', function () { + it('add', function () { const logic = { _add: [2, 3] }; expect(jsonLogic.apply(logic)).to.be.equal(5); }); - it('ceil', () => { + + it('ceil', function () { const logic = { _ceil: [4.006] }; expect(jsonLogic.apply(logic)).to.be.equal(5); }); - it('divide', () => { + + it('divide', function () { const logic = { _divide: [6, 3] }; expect(jsonLogic.apply(logic)).to.be.equal(2); }); - it('floor', () => { + + it('floor', function () { const logic = { _floor: [4.906] }; expect(jsonLogic.apply(logic)).to.be.equal(4); }); - it('max', () => { + + it('max', function () { const logic = { _max: [[2, 5, 6, 3]] }; expect(jsonLogic.apply(logic)).to.be.equal(6); }); - it('maxBy', () => { + + it('maxBy', function () { const data = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]; - const logic1 = { _maxBy: [{ 'var': '' }, 'n'] }; - const logic2 = { _maxBy: [{ 'var': '' }, { _property: 'n' }] }; + const logic1 = { _maxBy: [{ var: '' }, 'n'] }; + const logic2 = { _maxBy: [{ var: '' }, { _property: 'n' }] }; expect(jsonLogic.apply(logic1, data)).to.be.equal(data[2]); expect(jsonLogic.apply(logic2, data)).to.be.equal(data[2]); }); - it('mean', () => { + + it('mean', function () { const logic = { _mean: [[2, 5, 6, 3]] }; expect(jsonLogic.apply(logic)).to.be.equal(4); }); - it('meanBy', () => { + + it('meanBy', function () { const data = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]; - const logic1 = { _meanBy: [{ 'var': '' }, 'n'] }; - const logic2 = { _meanBy: [{ 'var': '' }, { _property: 'n' }] }; + const logic1 = { _meanBy: [{ var: '' }, 'n'] }; + const logic2 = { _meanBy: [{ var: '' }, { _property: 'n' }] }; expect(jsonLogic.apply(logic1, data)).to.be.equal(5); expect(jsonLogic.apply(logic2, data)).to.be.equal(5); }); - it('min', () => { + + it('min', function () { const logic = { _min: [[2, 5, 6, 3]] }; expect(jsonLogic.apply(logic)).to.be.equal(2); }); - it('minBy', () => { + + it('minBy', function () { const data = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]; - const logic1 = { _minBy: [{ 'var': '' }, 'n'] }; - const logic2 = { _minBy: [{ 'var': '' }, { _property: 'n' }] }; + const logic1 = { _minBy: [{ var: '' }, 'n'] }; + const logic2 = { _minBy: [{ var: '' }, { _property: 'n' }] }; expect(jsonLogic.apply(logic1, data)).to.be.equal(data[1]); expect(jsonLogic.apply(logic2, data)).to.be.equal(data[1]); }); - it('multiply', () => { + + it('multiply', function () { const logic = { _multiply: [2, 3] }; expect(jsonLogic.apply(logic)).to.be.equal(6); }); - it('round', () => { + + it('round', function () { const logic1 = { _round: [4.006] }; const logic2 = { _round: [4.906] }; expect(jsonLogic.apply(logic1)).to.be.equal(4); expect(jsonLogic.apply(logic2)).to.be.equal(5); }); - it('multiply', () => { - const logic = { _multiply: [2, 3] }; - expect(jsonLogic.apply(logic)).to.be.equal(6); - }); - it('subtract', () => { + + it('subtract', function () { const logic = { _subtract: [2, 3] }; expect(jsonLogic.apply(logic)).to.be.equal(-1); }); - it('sum', () => { + + it('sum', function () { const logic = { _sum: [[2, 3]] }; expect(jsonLogic.apply(logic)).to.be.equal(5); }); - it('sumBy', () => { + + it('sumBy', function () { const data = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]; - const logic1 = { _sumBy: [{ 'var': '' }, 'n'] }; - const logic2 = { _sumBy: [{ 'var': '' }, { _property: 'n' }] }; + const logic1 = { _sumBy: [{ var: '' }, 'n'] }; + const logic2 = { _sumBy: [{ var: '' }, { _property: 'n' }] }; expect(jsonLogic.apply(logic1, data)).to.be.equal(20); expect(jsonLogic.apply(logic2, data)).to.be.equal(20); }); }); - describe('Number', () => { - }); - describe('Object', () => { + describe('Number', function () {}); - }); - describe('String', () => { + describe('Object', function () {}); - }); - describe('Util', () => { - it('property', () => { - const data = [ - { 'a': { 'b': 2 } }, - { 'a': { 'b': 1 } } - ]; - const logic = { _sumBy: [{ 'var': '' }, { _property: 'a.b' }] }; + describe('String', function () {}); + + describe('Util', function () { + it('property', function () { + const data = [{ a: { b: 2 } }, { a: { b: 1 } }]; + const logic = { _sumBy: [{ var: '' }, { _property: 'a.b' }] }; expect(jsonLogic.apply(logic, data)).to.be.equal(3); }); }); diff --git a/src/modules/jsonlogic/index.ts b/src/modules/jsonlogic/index.ts index 43dbb31c..14b76cc8 100644 --- a/src/modules/jsonlogic/index.ts +++ b/src/modules/jsonlogic/index.ts @@ -1,78 +1,83 @@ import { BaseEvaluator, EvaluatorOptions } from 'utils'; import { jsonLogic } from './jsonLogic'; export class JSONLogicEvaluator extends BaseEvaluator { - public static evaluate( - func: any, - args: any = {}, - ret: any = '', - interpolate: boolean = false, - context: any = {}, - options: EvaluatorOptions = {} - ) { - let returnVal = null; - if (typeof func === 'object') { - try { - returnVal = jsonLogic.apply(func, args); - } - catch (err) { - returnVal = null; - console.warn(`An error occured within JSON Logic`, err); - } - } - else { - returnVal = BaseEvaluator.evaluate(func, args, ret, interpolate, context, options); - } - return returnVal; + public static evaluate( + func: any, + args: any = {}, + ret: any = '', + interpolate: boolean = false, + context: any = {}, + options: EvaluatorOptions = {}, + ) { + let returnVal = null; + if (typeof func === 'object') { + try { + returnVal = jsonLogic.apply(func, args); + } catch (err) { + returnVal = null; + console.warn(`An error occured within JSON Logic`, err); + } + } else { + returnVal = BaseEvaluator.evaluate(func, args, ret, interpolate, context, options); } + return returnVal; + } } export type EvaluatorContext = { - evalContext?: (context: any) => any; - instance?: any; - [key: string]: any; + evalContext?: (context: any) => any; + instance?: any; + [key: string]: any; }; export type EvaluatorFn = (context: EvaluatorContext) => any; export function evaluate( - context: EvaluatorContext, - evaluation: string, - ret: string = 'result', - evalContextFn?: EvaluatorFn, - options: EvaluatorOptions = {} + context: EvaluatorContext, + evaluation: string, + ret: string = 'result', + evalContextFn?: EvaluatorFn, + options: EvaluatorOptions = {}, ) { - const { evalContext, instance } = context; - const evalContextValue = evalContext ? evalContext(context) : context; - if (evalContextFn) { - evalContextFn(evalContextValue); - } - if (instance && (instance as any).evaluate) { - return (instance as any).evaluate(evaluation, evalContextValue, ret, false, options); - } - return (JSONLogicEvaluator as any).evaluate(evaluation, evalContextValue, ret, false, context, options); + const { evalContext, instance } = context; + const evalContextValue = evalContext ? evalContext(context) : context; + if (evalContextFn) { + evalContextFn(evalContextValue); + } + if (instance && (instance as any).evaluate) { + return (instance as any).evaluate(evaluation, evalContextValue, ret, false, options); + } + return (JSONLogicEvaluator as any).evaluate( + evaluation, + evalContextValue, + ret, + false, + context, + options, + ); } export function interpolate( - context: EvaluatorContext, - evaluation: string, - evalContextFn?: EvaluatorFn -) : string { - const { evalContext, instance } = context; - const evalContextValue = evalContext ? evalContext(context) : context; - if (evalContextFn) { - evalContextFn(evalContextValue); - } - if (instance && (instance as any).evaluate) { - return (instance as any).interpolate(evaluation, evalContextValue, { - noeval: true - }); - } - return (JSONLogicEvaluator as any).interpolate(evaluation, evalContextValue, { - noeval: true + context: EvaluatorContext, + evaluation: string, + evalContextFn?: EvaluatorFn, +): string { + const { evalContext, instance } = context; + const evalContextValue = evalContext ? evalContext(context) : context; + if (evalContextFn) { + evalContextFn(evalContextValue); + } + if (instance && (instance as any).evaluate) { + return (instance as any).interpolate(evaluation, evalContextValue, { + noeval: true, }); + } + return (JSONLogicEvaluator as any).interpolate(evaluation, evalContextValue, { + noeval: true, + }); } export * from './jsonLogic'; export const JSONLogicModule = { - evaluator: JSONLogicEvaluator, + evaluator: JSONLogicEvaluator, }; diff --git a/src/modules/jsonlogic/jsonLogic.ts b/src/modules/jsonlogic/jsonLogic.ts index c8830b4f..6f67b7b8 100644 --- a/src/modules/jsonlogic/jsonLogic.ts +++ b/src/modules/jsonlogic/jsonLogic.ts @@ -3,7 +3,7 @@ import { dayjs } from 'utils/date'; import { _ } from './operators'; // Configure JsonLogic -for (let operator in _) { +for (const operator in _) { jsonLogic.add_operation(`_${operator}`, _[operator]); } diff --git a/src/modules/jsonlogic/operators.ts b/src/modules/jsonlogic/operators.ts index 7ba431dc..afd83955 100644 --- a/src/modules/jsonlogic/operators.ts +++ b/src/modules/jsonlogic/operators.ts @@ -1,6 +1,6 @@ // Use only immutable useful functions from Lodash. // Visit https://lodash.com/docs for more info. -import { +import { chunk, compact, concat, @@ -244,7 +244,7 @@ import { stubTrue, times, toPath, - uniqueId + uniqueId, } from 'lodash'; export const _: any = { chunk, @@ -489,6 +489,5 @@ export const _: any = { stubTrue, times, toPath, - uniqueId + uniqueId, }; - diff --git a/src/process/__tests__/fixtures/addressComponentWithOtherCondComponents.json b/src/process/__tests__/fixtures/addressComponentWithOtherCondComponents.json index cdbd7bd4..60858ec3 100644 --- a/src/process/__tests__/fixtures/addressComponentWithOtherCondComponents.json +++ b/src/process/__tests__/fixtures/addressComponentWithOtherCondComponents.json @@ -125,10 +125,7 @@ { "long_name": "India", "short_name": "IN", - "types": [ - "country", - "political" - ] + "types": ["country", "political"] } ], "formatted_address": "India", @@ -145,10 +142,7 @@ } }, "place_id": "ChIJkbeSa_BfYzARphNChaFPjNc", - "types": [ - "country", - "political" - ], + "types": ["country", "political"], "formattedPlace": "India" }, "submit": true, @@ -156,4 +150,4 @@ "number": 1 } } -} \ No newline at end of file +} diff --git a/src/process/__tests__/fixtures/addressComponentWithOtherCondComponents2.json b/src/process/__tests__/fixtures/addressComponentWithOtherCondComponents2.json index c75d6433..36691922 100644 --- a/src/process/__tests__/fixtures/addressComponentWithOtherCondComponents2.json +++ b/src/process/__tests__/fixtures/addressComponentWithOtherCondComponents2.json @@ -137,4 +137,4 @@ "number2": 2 } } -} \ No newline at end of file +} diff --git a/src/process/__tests__/fixtures/data1a.json b/src/process/__tests__/fixtures/data1a.json index c525718b..f9f3afd2 100644 --- a/src/process/__tests__/fixtures/data1a.json +++ b/src/process/__tests__/fixtures/data1a.json @@ -1,230 +1,230 @@ { - "_id": "65777f801c5d0de6f55e2344", - "form": "657085d01c5d0de6f55de729", - "owner": "650a5bfdb9ac8160c0968e59", - "roles": [], - "access": [], - "metadata": { - "selectData": { - "state": { - "name": "Texas" + "_id": "65777f801c5d0de6f55e2344", + "form": "657085d01c5d0de6f55de729", + "owner": "650a5bfdb9ac8160c0968e59", + "roles": [], + "access": [], + "metadata": { + "selectData": { + "state": { + "name": "Texas" + } + }, + "timezone": "America/Chicago", + "offset": -360, + "origin": "https://form.local", + "referrer": "", + "browserName": "Netscape", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", + "pathName": "/", + "onLine": true, + "headers": { + "host": "form.local", + "x-real-ip": "172.18.0.1", + "x-forwarded-for": "172.18.0.1", + "x-forwarded-proto": "https", + "connection": "close", + "content-length": "4723", + "sec-ch-ua": "\"Brave\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\"", + "accept": "application/json", + "content-type": "application/json", + "sec-ch-ua-mobile": "?0", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", + "sec-ch-ua-platform": "\"macOS\"", + "sec-gpc": "1", + "accept-language": "en-US,en;q=0.5", + "origin": "https://form.local", + "sec-fetch-site": "same-origin", + "sec-fetch-mode": "cors", + "sec-fetch-dest": "empty", + "referer": "https://form.local/", + "accept-encoding": "gzip, deflate, br" + } + }, + "data": { + "taxRate": 0.08, + "customer": { + "firstName": "Joe", + "lastName": "Smith", + "email": "joe@example.com" + }, + "cc": "4444444444444", + "expires": "02/00/2030", + "state": "TX", + "zip": 75123, + "cart": [ + { + "product": { + "_id": "6570852c1c5d0de6f55de6ae", + "form": "657085141c5d0de6f55de4b7", + "owner": "650a5bfdb9ac8160c0968e59", + "roles": [], + "access": [], + "metadata": { + "timezone": "America/Chicago", + "offset": -360, + "origin": "https://form.local", + "referrer": "", + "browserName": "Netscape", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", + "pathName": "/", + "onLine": true, + "headers": { + "host": "form.local", + "x-real-ip": "172.18.0.1", + "x-forwarded-for": "172.18.0.1", + "x-forwarded-proto": "https", + "connection": "close", + "content-length": "374", + "sec-ch-ua": "\"Brave\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"", + "accept": "application/json", + "content-type": "application/json", + "sec-ch-ua-mobile": "?0", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", + "sec-ch-ua-platform": "\"macOS\"", + "sec-gpc": "1", + "accept-language": "en-US,en;q=0.5", + "origin": "https://form.local", + "sec-fetch-site": "same-origin", + "sec-fetch-mode": "cors", + "sec-fetch-dest": "empty", + "referer": "https://form.local/", + "accept-encoding": "gzip, deflate, br" } + }, + "data": { + "name": "C", + "sku": "C", + "price": 30 + }, + "_fvid": 0, + "project": "651185882e5eae71be60b314", + "state": "submitted", + "externalIds": [], + "created": "2023-12-06T14:29:00.345Z", + "modified": "2023-12-06T14:29:00.345Z" }, - "timezone": "America/Chicago", - "offset": -360, - "origin": "https://form.local", - "referrer": "", - "browserName": "Netscape", - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", - "pathName": "/", - "onLine": true, - "headers": { - "host": "form.local", - "x-real-ip": "172.18.0.1", - "x-forwarded-for": "172.18.0.1", - "x-forwarded-proto": "https", - "connection": "close", - "content-length": "4723", - "sec-ch-ua": "\"Brave\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\"", - "accept": "application/json", - "content-type": "application/json", - "sec-ch-ua-mobile": "?0", - "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", - "sec-ch-ua-platform": "\"macOS\"", - "sec-gpc": "1", - "accept-language": "en-US,en;q=0.5", + "quantity": 1, + "price": 30 + }, + { + "product": { + "_id": "657085261c5d0de6f55de612", + "form": "657085141c5d0de6f55de4b7", + "owner": "650a5bfdb9ac8160c0968e59", + "roles": [], + "access": [], + "metadata": { + "timezone": "America/Chicago", + "offset": -360, "origin": "https://form.local", - "sec-fetch-site": "same-origin", - "sec-fetch-mode": "cors", - "sec-fetch-dest": "empty", - "referer": "https://form.local/", - "accept-encoding": "gzip, deflate, br" - } - }, - "data": { - "taxRate": 0.08, - "customer": { - "firstName": "Joe", - "lastName": "Smith", - "email": "joe@example.com" + "referrer": "", + "browserName": "Netscape", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", + "pathName": "/", + "onLine": true, + "headers": { + "host": "form.local", + "x-real-ip": "172.18.0.1", + "x-forwarded-for": "172.18.0.1", + "x-forwarded-proto": "https", + "connection": "close", + "content-length": "374", + "sec-ch-ua": "\"Brave\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"", + "accept": "application/json", + "content-type": "application/json", + "sec-ch-ua-mobile": "?0", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", + "sec-ch-ua-platform": "\"macOS\"", + "sec-gpc": "1", + "accept-language": "en-US,en;q=0.5", + "origin": "https://form.local", + "sec-fetch-site": "same-origin", + "sec-fetch-mode": "cors", + "sec-fetch-dest": "empty", + "referer": "https://form.local/", + "accept-encoding": "gzip, deflate, br" + } + }, + "data": { + "name": "B", + "sku": "B", + "price": 20 + }, + "_fvid": 0, + "project": "651185882e5eae71be60b314", + "state": "submitted", + "externalIds": [], + "created": "2023-12-06T14:28:54.747Z", + "modified": "2023-12-06T14:28:54.748Z" }, - "cc": "4444444444444", - "expires": "02/00/2030", - "state": "TX", - "zip": 75123, - "cart": [ - { - "product": { - "_id": "6570852c1c5d0de6f55de6ae", - "form": "657085141c5d0de6f55de4b7", - "owner": "650a5bfdb9ac8160c0968e59", - "roles": [], - "access": [], - "metadata": { - "timezone": "America/Chicago", - "offset": -360, - "origin": "https://form.local", - "referrer": "", - "browserName": "Netscape", - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", - "pathName": "/", - "onLine": true, - "headers": { - "host": "form.local", - "x-real-ip": "172.18.0.1", - "x-forwarded-for": "172.18.0.1", - "x-forwarded-proto": "https", - "connection": "close", - "content-length": "374", - "sec-ch-ua": "\"Brave\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"", - "accept": "application/json", - "content-type": "application/json", - "sec-ch-ua-mobile": "?0", - "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", - "sec-ch-ua-platform": "\"macOS\"", - "sec-gpc": "1", - "accept-language": "en-US,en;q=0.5", - "origin": "https://form.local", - "sec-fetch-site": "same-origin", - "sec-fetch-mode": "cors", - "sec-fetch-dest": "empty", - "referer": "https://form.local/", - "accept-encoding": "gzip, deflate, br" - } - }, - "data": { - "name": "C", - "sku": "C", - "price": 30 - }, - "_fvid": 0, - "project": "651185882e5eae71be60b314", - "state": "submitted", - "externalIds": [], - "created": "2023-12-06T14:29:00.345Z", - "modified": "2023-12-06T14:29:00.345Z" - }, - "quantity": 1, - "price": 30 - }, - { - "product": { - "_id": "657085261c5d0de6f55de612", - "form": "657085141c5d0de6f55de4b7", - "owner": "650a5bfdb9ac8160c0968e59", - "roles": [], - "access": [], - "metadata": { - "timezone": "America/Chicago", - "offset": -360, - "origin": "https://form.local", - "referrer": "", - "browserName": "Netscape", - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", - "pathName": "/", - "onLine": true, - "headers": { - "host": "form.local", - "x-real-ip": "172.18.0.1", - "x-forwarded-for": "172.18.0.1", - "x-forwarded-proto": "https", - "connection": "close", - "content-length": "374", - "sec-ch-ua": "\"Brave\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"", - "accept": "application/json", - "content-type": "application/json", - "sec-ch-ua-mobile": "?0", - "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", - "sec-ch-ua-platform": "\"macOS\"", - "sec-gpc": "1", - "accept-language": "en-US,en;q=0.5", - "origin": "https://form.local", - "sec-fetch-site": "same-origin", - "sec-fetch-mode": "cors", - "sec-fetch-dest": "empty", - "referer": "https://form.local/", - "accept-encoding": "gzip, deflate, br" - } - }, - "data": { - "name": "B", - "sku": "B", - "price": 20 - }, - "_fvid": 0, - "project": "651185882e5eae71be60b314", - "state": "submitted", - "externalIds": [], - "created": "2023-12-06T14:28:54.747Z", - "modified": "2023-12-06T14:28:54.748Z" - }, - "quantity": 2, - "price": 20 - }, - { - "product": { - "_id": "6570851e1c5d0de6f55de576", - "form": "657085141c5d0de6f55de4b7", - "owner": "650a5bfdb9ac8160c0968e59", - "roles": [], - "access": [], - "metadata": { - "timezone": "America/Chicago", - "offset": -360, - "origin": "https://form.local", - "referrer": "", - "browserName": "Netscape", - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", - "pathName": "/", - "onLine": true, - "headers": { - "host": "form.local", - "x-real-ip": "172.18.0.1", - "x-forwarded-for": "172.18.0.1", - "x-forwarded-proto": "https", - "connection": "close", - "content-length": "374", - "sec-ch-ua": "\"Brave\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"", - "accept": "application/json", - "content-type": "application/json", - "sec-ch-ua-mobile": "?0", - "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", - "sec-ch-ua-platform": "\"macOS\"", - "sec-gpc": "1", - "accept-language": "en-US,en;q=0.5", - "origin": "https://form.local", - "sec-fetch-site": "same-origin", - "sec-fetch-mode": "cors", - "sec-fetch-dest": "empty", - "referer": "https://form.local/", - "accept-encoding": "gzip, deflate, br" - } - }, - "data": { - "name": "A", - "sku": "A", - "price": 10 - }, - "_fvid": 0, - "project": "651185882e5eae71be60b314", - "state": "submitted", - "externalIds": [], - "created": "2023-12-06T14:28:46.759Z", - "modified": "2023-12-06T14:28:46.760Z" - }, - "quantity": 3, - "price": 10 + "quantity": 2, + "price": 20 + }, + { + "product": { + "_id": "6570851e1c5d0de6f55de576", + "form": "657085141c5d0de6f55de4b7", + "owner": "650a5bfdb9ac8160c0968e59", + "roles": [], + "access": [], + "metadata": { + "timezone": "America/Chicago", + "offset": -360, + "origin": "https://form.local", + "referrer": "", + "browserName": "Netscape", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", + "pathName": "/", + "onLine": true, + "headers": { + "host": "form.local", + "x-real-ip": "172.18.0.1", + "x-forwarded-for": "172.18.0.1", + "x-forwarded-proto": "https", + "connection": "close", + "content-length": "374", + "sec-ch-ua": "\"Brave\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"", + "accept": "application/json", + "content-type": "application/json", + "sec-ch-ua-mobile": "?0", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", + "sec-ch-ua-platform": "\"macOS\"", + "sec-gpc": "1", + "accept-language": "en-US,en;q=0.5", + "origin": "https://form.local", + "sec-fetch-site": "same-origin", + "sec-fetch-mode": "cors", + "sec-fetch-dest": "empty", + "referer": "https://form.local/", + "accept-encoding": "gzip, deflate, br" } - ], - "subtotal": 100, - "hasTaxes": true, - "taxes": 8, - "total": 108 - }, - "_fvid": 0, - "project": "651185882e5eae71be60b314", - "state": "submitted", - "externalIds": [], - "created": "2023-12-11T21:30:40.162Z", - "modified": "2023-12-11T21:30:40.162Z" -} \ No newline at end of file + }, + "data": { + "name": "A", + "sku": "A", + "price": 10 + }, + "_fvid": 0, + "project": "651185882e5eae71be60b314", + "state": "submitted", + "externalIds": [], + "created": "2023-12-06T14:28:46.759Z", + "modified": "2023-12-06T14:28:46.760Z" + }, + "quantity": 3, + "price": 10 + } + ], + "subtotal": 100, + "hasTaxes": true, + "taxes": 8, + "total": 108 + }, + "_fvid": 0, + "project": "651185882e5eae71be60b314", + "state": "submitted", + "externalIds": [], + "created": "2023-12-11T21:30:40.162Z", + "modified": "2023-12-11T21:30:40.162Z" +} diff --git a/src/process/__tests__/fixtures/forDataGridRequired.json b/src/process/__tests__/fixtures/forDataGridRequired.json index 30aec20e..9e2f76bb 100644 --- a/src/process/__tests__/fixtures/forDataGridRequired.json +++ b/src/process/__tests__/fixtures/forDataGridRequired.json @@ -13,9 +13,7 @@ "enableRowGroups": false, "initEmpty": false, "tableView": false, - "defaultValue": [ - {} - ], + "defaultValue": [{}], "validate": { "required": true }, @@ -78,14 +76,12 @@ }, "submission": { "data": { - - "dataGrid": [ - { - "textField": "" - } - ], - "submit": true + "dataGrid": [ + { + "textField": "" + } + ], + "submit": true } - - } -} \ No newline at end of file + } +} diff --git a/src/process/__tests__/fixtures/form1.json b/src/process/__tests__/fixtures/form1.json index 8fdafbfb..92f17cbc 100644 --- a/src/process/__tests__/fixtures/form1.json +++ b/src/process/__tests__/fixtures/form1.json @@ -1,706 +1,702 @@ { - "_id": "657085d01c5d0de6f55de729", - "title": "Checkout", - "name": "checkout", - "path": "checkout", - "type": "form", - "display": "form", - "tags": [ ], - "access": [ - { - "type": "create_own", - "roles": [ ] + "_id": "657085d01c5d0de6f55de729", + "title": "Checkout", + "name": "checkout", + "path": "checkout", + "type": "form", + "display": "form", + "tags": [], + "access": [ + { + "type": "create_own", + "roles": [] + }, + { + "type": "create_all", + "roles": [] + }, + { + "type": "read_own", + "roles": [] + }, + { + "type": "read_all", + "roles": ["651185882e5eae71be60b31b", "651185882e5eae71be60b31f", "651185882e5eae71be60b323"] + }, + { + "type": "update_own", + "roles": [] + }, + { + "type": "update_all", + "roles": [] + }, + { + "type": "delete_own", + "roles": [] + }, + { + "type": "delete_all", + "roles": [] + }, + { + "type": "team_read", + "roles": [] + }, + { + "type": "team_write", + "roles": [] + }, + { + "type": "team_admin", + "roles": [] + } + ], + "submissionAccess": [ + { + "type": "create_own", + "roles": [] + }, + { + "type": "create_all", + "roles": [] + }, + { + "type": "read_own", + "roles": [] + }, + { + "type": "read_all", + "roles": [] + }, + { + "type": "update_own", + "roles": [] + }, + { + "type": "update_all", + "roles": [] + }, + { + "type": "delete_own", + "roles": [] + }, + { + "type": "delete_all", + "roles": [] + }, + { + "type": "team_read", + "roles": [] + }, + { + "type": "team_write", + "roles": [] + }, + { + "type": "team_admin", + "roles": [] + } + ], + "owner": "650a5bfdb9ac8160c0968e59", + "components": [ + { + "label": "Products", + "persistent": "client-only", + "trigger": { + "init": true, + "server": true }, - { - "type": "create_all", - "roles": [ ] - }, - { - "type": "read_own", - "roles": [ ] - }, - { - "type": "read_all", - "roles": [ - "651185882e5eae71be60b31b", - "651185882e5eae71be60b31f", - "651185882e5eae71be60b323" - ] - }, - { - "type": "update_own", - "roles": [ ] - }, - { - "type": "update_all", - "roles": [ ] - }, - { - "type": "delete_own", - "roles": [ ] - }, - { - "type": "delete_all", - "roles": [ ] - }, - { - "type": "team_read", - "roles": [ ] - }, - { - "type": "team_write", - "roles": [ ] - }, - { - "type": "team_admin", - "roles": [ ] - } - ], - "submissionAccess": [ - { - "type": "create_own", - "roles": [ ] - }, - { - "type": "create_all", - "roles": [ ] - }, - { - "type": "read_own", - "roles": [ ] - }, - { - "type": "read_all", - "roles": [ ] - }, - { - "type": "update_own", - "roles": [ ] - }, - { - "type": "update_all", - "roles": [ ] - }, - { - "type": "delete_own", - "roles": [ ] - }, - { - "type": "delete_all", - "roles": [ ] - }, - { - "type": "team_read", - "roles": [ ] - }, - { - "type": "team_write", - "roles": [ ] + "dataSrc": "url", + "fetch": { + "url": "https://form.local/sandbox/product/submission", + "method": "get", + "headers": [ + { + "key": "", + "value": "" + } + ], + "mapFunction": "", + "forwardHeaders": false, + "authenticate": true }, - { - "type": "team_admin", - "roles": [ ] - } - ], - "owner": "650a5bfdb9ac8160c0968e59", - "components": [ - { - "label": "Products", - "persistent": "client-only", - "trigger": { - "init": true, - "server": true - }, - "dataSrc": "url", - "fetch": { - "url": "https://form.local/sandbox/product/submission", - "method": "get", - "headers": [ + "allowCaching": true, + "key": "products", + "type": "datasource", + "input": true, + "tableView": false + }, + { + "label": "Tax Rate", + "customDefaultValue": "value = 0.08;", + "key": "taxRate", + "type": "hidden", + "input": true, + "tableView": false + }, + { + "label": "Customer", + "tableView": false, + "key": "customer", + "type": "container", + "input": true, + "components": [ + { + "label": "Columns", + "columns": [ + { + "components": [ + { + "label": "First Name", + "applyMaskOn": "change", + "tableView": true, + "key": "firstName", + "type": "textfield", + "input": true + }, + { + "label": "Last Name", + "applyMaskOn": "change", + "tableView": true, + "key": "lastName", + "type": "textfield", + "input": true + } + ], + "width": 6, + "offset": 0, + "push": 0, + "pull": 0, + "size": "md", + "currentWidth": 6 + }, { - "key": "", - "value": "" + "components": [ + { + "label": "Email", + "applyMaskOn": "change", + "tableView": true, + "key": "email", + "type": "email", + "input": true + } + ], + "width": 6, + "offset": 0, + "push": 0, + "pull": 0, + "size": "md", + "currentWidth": 6 } ], - "mapFunction": "", - "forwardHeaders": false, - "authenticate": true + "key": "columns", + "type": "columns", + "input": false, + "tableView": false + } + ] + }, + { + "title": "Payment Information", + "collapsible": false, + "key": "paymentInformation", + "type": "panel", + "label": "Panel", + "input": false, + "tableView": false, + "components": [ + { + "label": "CC#", + "applyMaskOn": "change", + "tableView": true, + "validate": { + "pattern": "^4[0-9]{12}(?:[0-9]{3})?$", + "customMessage": "Must be a valid Visa credit card number" + }, + "key": "cc", + "type": "textfield", + "input": true }, - "allowCaching": true, - "key": "products", - "type": "datasource", - "input": true, - "tableView": false - }, - { - "label": "Tax Rate", - "customDefaultValue": "value = 0.08;", - "key": "taxRate", - "type": "hidden", - "input": true, - "tableView": false - }, - { - "label": "Customer", - "tableView": false, - "key": "customer", - "type": "container", - "input": true, - "components": [ - { - "label": "Columns", - "columns": [ + { + "label": "Expires", + "hideInputLabels": false, + "inputsLabelPosition": "top", + "useLocaleSettings": false, + "tableView": false, + "fields": { + "day": { + "hide": true + }, + "month": { + "hide": false, + "required": true + }, + "year": { + "hide": false, + "required": true + } + }, + "defaultValue": "00/00/0000", + "validation": { + "minDate": "moment()" + }, + "key": "expires", + "type": "day", + "input": true + }, + { + "label": "State", + "widget": "choicesjs", + "tableView": true, + "dataSrc": "json", + "data": { + "json": [ { - "components": [ - { - "label": "First Name", - "applyMaskOn": "change", - "tableView": true, - "key": "firstName", - "type": "textfield", - "input": true - }, - { - "label": "Last Name", - "applyMaskOn": "change", - "tableView": true, - "key": "lastName", - "type": "textfield", - "input": true - } - ], - "width": 6, - "offset": 0, - "push": 0, - "pull": 0, - "size": "md", - "currentWidth": 6 + "name": "Alabama", + "abbreviation": "AL" }, { - "components": [ - { - "label": "Email", - "applyMaskOn": "change", - "tableView": true, - "key": "email", - "type": "email", - "input": true - } - ], - "width": 6, - "offset": 0, - "push": 0, - "pull": 0, - "size": "md", - "currentWidth": 6 + "name": "Alaska", + "abbreviation": "AK" + }, + { + "name": "American Samoa", + "abbreviation": "AS" + }, + { + "name": "Arizona", + "abbreviation": "AZ" + }, + { + "name": "Arkansas", + "abbreviation": "AR" + }, + { + "name": "California", + "abbreviation": "CA" + }, + { + "name": "Colorado", + "abbreviation": "CO" + }, + { + "name": "Connecticut", + "abbreviation": "CT" + }, + { + "name": "Delaware", + "abbreviation": "DE" + }, + { + "name": "District Of Columbia", + "abbreviation": "DC" + }, + { + "name": "Federated States Of Micronesia", + "abbreviation": "FM" + }, + { + "name": "Florida", + "abbreviation": "FL" + }, + { + "name": "Georgia", + "abbreviation": "GA" + }, + { + "name": "Guam", + "abbreviation": "GU" + }, + { + "name": "Hawaii", + "abbreviation": "HI" + }, + { + "name": "Idaho", + "abbreviation": "ID" + }, + { + "name": "Illinois", + "abbreviation": "IL" + }, + { + "name": "Indiana", + "abbreviation": "IN" + }, + { + "name": "Iowa", + "abbreviation": "IA" + }, + { + "name": "Kansas", + "abbreviation": "KS" + }, + { + "name": "Kentucky", + "abbreviation": "KY" + }, + { + "name": "Louisiana", + "abbreviation": "LA" + }, + { + "name": "Maine", + "abbreviation": "ME" + }, + { + "name": "Marshall Islands", + "abbreviation": "MH" + }, + { + "name": "Maryland", + "abbreviation": "MD" + }, + { + "name": "Massachusetts", + "abbreviation": "MA" + }, + { + "name": "Michigan", + "abbreviation": "MI" + }, + { + "name": "Minnesota", + "abbreviation": "MN" + }, + { + "name": "Mississippi", + "abbreviation": "MS" + }, + { + "name": "Missouri", + "abbreviation": "MO" + }, + { + "name": "Montana", + "abbreviation": "MT" + }, + { + "name": "Nebraska", + "abbreviation": "NE" + }, + { + "name": "Nevada", + "abbreviation": "NV" + }, + { + "name": "New Hampshire", + "abbreviation": "NH" + }, + { + "name": "New Jersey", + "abbreviation": "NJ" + }, + { + "name": "New Mexico", + "abbreviation": "NM" + }, + { + "name": "New York", + "abbreviation": "NY" + }, + { + "name": "North Carolina", + "abbreviation": "NC" + }, + { + "name": "North Dakota", + "abbreviation": "ND" + }, + { + "name": "Northern Mariana Islands", + "abbreviation": "MP" + }, + { + "name": "Ohio", + "abbreviation": "OH" + }, + { + "name": "Oklahoma", + "abbreviation": "OK" + }, + { + "name": "Oregon", + "abbreviation": "OR" + }, + { + "name": "Palau", + "abbreviation": "PW" + }, + { + "name": "Pennsylvania", + "abbreviation": "PA" + }, + { + "name": "Puerto Rico", + "abbreviation": "PR" + }, + { + "name": "Rhode Island", + "abbreviation": "RI" + }, + { + "name": "South Carolina", + "abbreviation": "SC" + }, + { + "name": "South Dakota", + "abbreviation": "SD" + }, + { + "name": "Tennessee", + "abbreviation": "TN" + }, + { + "name": "Texas", + "abbreviation": "TX" + }, + { + "name": "Utah", + "abbreviation": "UT" + }, + { + "name": "Vermont", + "abbreviation": "VT" + }, + { + "name": "Virgin Islands", + "abbreviation": "VI" + }, + { + "name": "Virginia", + "abbreviation": "VA" + }, + { + "name": "Washington", + "abbreviation": "WA" + }, + { + "name": "West Virginia", + "abbreviation": "WV" + }, + { + "name": "Wisconsin", + "abbreviation": "WI" + }, + { + "name": "Wyoming", + "abbreviation": "WY" } - ], - "key": "columns", - "type": "columns", - "input": false, - "tableView": false - } - ] - }, - { - "title": "Payment Information", - "collapsible": false, - "key": "paymentInformation", - "type": "panel", - "label": "Panel", - "input": false, - "tableView": false, - "components": [ - { - "label": "CC#", - "applyMaskOn": "change", - "tableView": true, - "validate": { - "pattern": "^4[0-9]{12}(?:[0-9]{3})?$", - "customMessage": "Must be a valid Visa credit card number" - }, - "key": "cc", - "type": "textfield", - "input": true + ] }, - { - "label": "Expires", - "hideInputLabels": false, - "inputsLabelPosition": "top", - "useLocaleSettings": false, - "tableView": false, - "fields": { - "day": { - "hide": true - }, - "month": { - "hide": false, - "required": true - }, - "year": { - "hide": false, - "required": true - } - }, - "defaultValue": "00/00/0000", - "validation": { - "minDate": "moment()" - }, - "key": "expires", - "type": "day", - "input": true + "valueProperty": "abbreviation", + "template": "{{ item.name }}", + "validate": { + "onlyAvailableItems": true }, - { - "label": "State", - "widget": "choicesjs", - "tableView": true, - "dataSrc": "json", - "data": { - "json": [ - { - "name": "Alabama", - "abbreviation": "AL" - }, - { - "name": "Alaska", - "abbreviation": "AK" - }, - { - "name": "American Samoa", - "abbreviation": "AS" - }, - { - "name": "Arizona", - "abbreviation": "AZ" - }, - { - "name": "Arkansas", - "abbreviation": "AR" - }, - { - "name": "California", - "abbreviation": "CA" - }, - { - "name": "Colorado", - "abbreviation": "CO" - }, - { - "name": "Connecticut", - "abbreviation": "CT" - }, - { - "name": "Delaware", - "abbreviation": "DE" - }, - { - "name": "District Of Columbia", - "abbreviation": "DC" - }, - { - "name": "Federated States Of Micronesia", - "abbreviation": "FM" - }, - { - "name": "Florida", - "abbreviation": "FL" - }, - { - "name": "Georgia", - "abbreviation": "GA" - }, - { - "name": "Guam", - "abbreviation": "GU" - }, - { - "name": "Hawaii", - "abbreviation": "HI" - }, - { - "name": "Idaho", - "abbreviation": "ID" - }, - { - "name": "Illinois", - "abbreviation": "IL" - }, - { - "name": "Indiana", - "abbreviation": "IN" - }, - { - "name": "Iowa", - "abbreviation": "IA" - }, - { - "name": "Kansas", - "abbreviation": "KS" - }, - { - "name": "Kentucky", - "abbreviation": "KY" - }, - { - "name": "Louisiana", - "abbreviation": "LA" - }, - { - "name": "Maine", - "abbreviation": "ME" - }, - { - "name": "Marshall Islands", - "abbreviation": "MH" - }, - { - "name": "Maryland", - "abbreviation": "MD" - }, - { - "name": "Massachusetts", - "abbreviation": "MA" - }, - { - "name": "Michigan", - "abbreviation": "MI" - }, - { - "name": "Minnesota", - "abbreviation": "MN" - }, - { - "name": "Mississippi", - "abbreviation": "MS" - }, - { - "name": "Missouri", - "abbreviation": "MO" - }, - { - "name": "Montana", - "abbreviation": "MT" - }, - { - "name": "Nebraska", - "abbreviation": "NE" - }, - { - "name": "Nevada", - "abbreviation": "NV" - }, - { - "name": "New Hampshire", - "abbreviation": "NH" - }, - { - "name": "New Jersey", - "abbreviation": "NJ" - }, - { - "name": "New Mexico", - "abbreviation": "NM" - }, - { - "name": "New York", - "abbreviation": "NY" - }, - { - "name": "North Carolina", - "abbreviation": "NC" - }, - { - "name": "North Dakota", - "abbreviation": "ND" - }, - { - "name": "Northern Mariana Islands", - "abbreviation": "MP" - }, - { - "name": "Ohio", - "abbreviation": "OH" - }, - { - "name": "Oklahoma", - "abbreviation": "OK" - }, - { - "name": "Oregon", - "abbreviation": "OR" - }, - { - "name": "Palau", - "abbreviation": "PW" - }, - { - "name": "Pennsylvania", - "abbreviation": "PA" - }, - { - "name": "Puerto Rico", - "abbreviation": "PR" - }, - { - "name": "Rhode Island", - "abbreviation": "RI" - }, - { - "name": "South Carolina", - "abbreviation": "SC" - }, - { - "name": "South Dakota", - "abbreviation": "SD" - }, - { - "name": "Tennessee", - "abbreviation": "TN" - }, - { - "name": "Texas", - "abbreviation": "TX" - }, - { - "name": "Utah", - "abbreviation": "UT" - }, - { - "name": "Vermont", - "abbreviation": "VT" - }, - { - "name": "Virgin Islands", - "abbreviation": "VI" - }, - { - "name": "Virginia", - "abbreviation": "VA" - }, - { - "name": "Washington", - "abbreviation": "WA" - }, - { - "name": "West Virginia", - "abbreviation": "WV" - }, - { - "name": "Wisconsin", - "abbreviation": "WI" - }, - { - "name": "Wyoming", - "abbreviation": "WY" - } - ] - }, - "valueProperty": "abbreviation", - "template": "{{ item.name }}", - "validate": { - "onlyAvailableItems": true - }, - "key": "state", - "type": "select", - "input": true + "key": "state", + "type": "select", + "input": true + }, + { + "label": "ZIP", + "applyMaskOn": "change", + "mask": false, + "tableView": false, + "delimiter": false, + "requireDecimal": false, + "inputFormat": "plain", + "truncateMultipleSpaces": false, + "validate": { + "min": 70000, + "max": 76000 }, - { - "label": "ZIP", - "applyMaskOn": "change", - "mask": false, - "tableView": false, - "delimiter": false, - "requireDecimal": false, - "inputFormat": "plain", - "truncateMultipleSpaces": false, - "validate": { - "min": 70000, - "max": 76000 - }, - "key": "zip", - "type": "number", - "input": true - } - ] - }, - { - "label": "Cart", - "reorder": false, - "addAnotherPosition": "bottom", - "layoutFixed": false, - "enableRowGroups": false, - "initEmpty": false, - "tableView": false, - "defaultValue": [ - { - "product": { } - } - ], - "key": "cart", - "type": "datagrid", - "input": true, - "components": [ - { - "label": "Product", - "widget": "choicesjs", - "tableView": true, - "dataSrc": "resource", - "data": { - "resource": "657085141c5d0de6f55de4b7" - }, - "template": "{{ item.data.name }}", - "key": "product", - "type": "select", - "input": true, - "noRefreshOnScroll": false, - "addResource": false, - "reference": false + "key": "zip", + "type": "number", + "input": true + } + ] + }, + { + "label": "Cart", + "reorder": false, + "addAnotherPosition": "bottom", + "layoutFixed": false, + "enableRowGroups": false, + "initEmpty": false, + "tableView": false, + "defaultValue": [ + { + "product": {} + } + ], + "key": "cart", + "type": "datagrid", + "input": true, + "components": [ + { + "label": "Product", + "widget": "choicesjs", + "tableView": true, + "dataSrc": "resource", + "data": { + "resource": "657085141c5d0de6f55de4b7" }, - { - "label": "Price", - "applyMaskOn": "change", - "mask": false, - "spellcheck": true, - "tableView": false, - "currency": "USD", - "inputFormat": "plain", - "truncateMultipleSpaces": false, - "calculateValue": "if (\n data.products && \n data.products.length && \n row.product &&\n row.product.data\n) {\n var selected = row.product.data.sku;\n data.products.forEach(function(product) {\n if (product && product.data.sku === row.product.data.sku) {\n value = product.data.price;\n }\n });\n}", - "calculateServer": true, - "key": "price", - "type": "currency", - "input": true, - "delimiter": true + "template": "{{ item.data.name }}", + "key": "product", + "type": "select", + "input": true, + "noRefreshOnScroll": false, + "addResource": false, + "reference": false + }, + { + "label": "Price", + "applyMaskOn": "change", + "mask": false, + "spellcheck": true, + "tableView": false, + "currency": "USD", + "inputFormat": "plain", + "truncateMultipleSpaces": false, + "calculateValue": "if (\n data.products && \n data.products.length && \n row.product &&\n row.product.data\n) {\n var selected = row.product.data.sku;\n data.products.forEach(function(product) {\n if (product && product.data.sku === row.product.data.sku) {\n value = product.data.price;\n }\n });\n}", + "calculateServer": true, + "key": "price", + "type": "currency", + "input": true, + "delimiter": true + }, + { + "label": "Quantity", + "applyMaskOn": "change", + "mask": false, + "tableView": false, + "delimiter": false, + "requireDecimal": false, + "inputFormat": "plain", + "truncateMultipleSpaces": false, + "validate": { + "min": 1, + "max": 5 }, - { - "label": "Quantity", - "applyMaskOn": "change", - "mask": false, - "tableView": false, - "delimiter": false, - "requireDecimal": false, - "inputFormat": "plain", - "truncateMultipleSpaces": false, - "validate": { - "min": 1, - "max": 5 + "key": "quantity", + "type": "number", + "input": true, + "defaultValue": 1 + } + ] + }, + { + "label": "Columns", + "columns": [ + { + "components": [], + "width": 6, + "offset": 0, + "push": 0, + "pull": 0, + "size": "md", + "currentWidth": 6 + }, + { + "components": [ + { + "label": "Sub Total", + "applyMaskOn": "change", + "mask": false, + "spellcheck": true, + "tableView": false, + "currency": "USD", + "inputFormat": "plain", + "truncateMultipleSpaces": false, + "redrawOn": "cart", + "calculateValue": "value = data.cart.reduce((acc, item) => {\n if (!item.price) {\n return acc;\n }\n return acc + (item.price * item.quantity);\n}, 0);", + "key": "subtotal", + "type": "currency", + "input": true, + "delimiter": true }, - "key": "quantity", - "type": "number", - "input": true, - "defaultValue": 1 - } - ] - }, - { - "label": "Columns", - "columns": [ - { - "components": [ ], - "width": 6, - "offset": 0, - "push": 0, - "pull": 0, - "size": "md", - "currentWidth": 6 - }, - { - "components": [ - { - "label": "Sub Total", - "applyMaskOn": "change", - "mask": false, - "spellcheck": true, - "tableView": false, - "currency": "USD", - "inputFormat": "plain", - "truncateMultipleSpaces": false, - "redrawOn": "cart", - "calculateValue": "value = data.cart.reduce((acc, item) => {\n if (!item.price) {\n return acc;\n }\n return acc + (item.price * item.quantity);\n}, 0);", - "key": "subtotal", - "type": "currency", - "input": true, - "delimiter": true - }, - { - "label": "Has Taxes", - "tableView": false, - "key": "hasTaxes", - "type": "checkbox", - "input": true, - "defaultValue": false - }, - { - "label": "Taxes", - "applyMaskOn": "change", - "mask": false, - "spellcheck": true, - "tableView": false, - "currency": "USD", - "inputFormat": "plain", - "truncateMultipleSpaces": false, - "calculateValue": "value = data.subtotal * data.taxRate;", - "key": "taxes", - "conditional": { - "show": true, - "conjunction": "all", - "conditions": [ - { - "component": "hasTaxes", - "operator": "isEqual", - "value": true - } - ] - }, - "type": "currency", - "input": true, - "delimiter": true - }, - { - "label": "Total", - "applyMaskOn": "change", - "mask": false, - "spellcheck": true, - "tableView": false, - "currency": "USD", - "inputFormat": "plain", - "truncateMultipleSpaces": false, - "calculateValue": "value = data.subtotal;\nif (data.taxes) {\n value += data.taxes;\n}", - "key": "total", - "type": "currency", - "input": true, - "delimiter": true - } - ], - "width": 6, - "offset": 0, - "push": 0, - "pull": 0, - "size": "md", - "currentWidth": 6 - } - ], - "key": "columns", - "type": "columns", - "input": false, - "tableView": false - }, - { - "type": "button", - "label": "Submit", - "key": "submit", - "disableOnInvalid": true, - "input": true, - "tableView": false - } - ], - "settings": { }, - "properties": { }, - "project": "651185882e5eae71be60b314", - "controller": "", - "revisions": "", - "submissionRevisions": "", - "_vid": 0, - "created": "2023-12-06T14:31:44.392Z", - "modified": "2023-12-11T21:29:26.320Z", - "machineName": "sandbox:checkout" - } \ No newline at end of file + { + "label": "Has Taxes", + "tableView": false, + "key": "hasTaxes", + "type": "checkbox", + "input": true, + "defaultValue": false + }, + { + "label": "Taxes", + "applyMaskOn": "change", + "mask": false, + "spellcheck": true, + "tableView": false, + "currency": "USD", + "inputFormat": "plain", + "truncateMultipleSpaces": false, + "calculateValue": "value = data.subtotal * data.taxRate;", + "key": "taxes", + "conditional": { + "show": true, + "conjunction": "all", + "conditions": [ + { + "component": "hasTaxes", + "operator": "isEqual", + "value": true + } + ] + }, + "type": "currency", + "input": true, + "delimiter": true + }, + { + "label": "Total", + "applyMaskOn": "change", + "mask": false, + "spellcheck": true, + "tableView": false, + "currency": "USD", + "inputFormat": "plain", + "truncateMultipleSpaces": false, + "calculateValue": "value = data.subtotal;\nif (data.taxes) {\n value += data.taxes;\n}", + "key": "total", + "type": "currency", + "input": true, + "delimiter": true + } + ], + "width": 6, + "offset": 0, + "push": 0, + "pull": 0, + "size": "md", + "currentWidth": 6 + } + ], + "key": "columns", + "type": "columns", + "input": false, + "tableView": false + }, + { + "type": "button", + "label": "Submit", + "key": "submit", + "disableOnInvalid": true, + "input": true, + "tableView": false + } + ], + "settings": {}, + "properties": {}, + "project": "651185882e5eae71be60b314", + "controller": "", + "revisions": "", + "submissionRevisions": "", + "_vid": 0, + "created": "2023-12-06T14:31:44.392Z", + "modified": "2023-12-11T21:29:26.320Z", + "machineName": "sandbox:checkout" +} diff --git a/src/process/__tests__/fixtures/index.ts b/src/process/__tests__/fixtures/index.ts index b0fefb35..2a576ef6 100644 --- a/src/process/__tests__/fixtures/index.ts +++ b/src/process/__tests__/fixtures/index.ts @@ -10,4 +10,16 @@ import data1a from './data1a.json'; import form1 from './form1.json'; import subs from './subs.json'; -export { addressComponentWithOtherCondComponents, addressComponentWithOtherCondComponents2, clearOnHideWithCustomCondition, clearOnHideWithHiddenParent, skipValidForLogicallyHiddenComp, skipValidForConditionallyHiddenComp, skipValidWithHiddenParentComp, forDataGridRequired, data1a, form1, subs }; +export { + addressComponentWithOtherCondComponents, + addressComponentWithOtherCondComponents2, + clearOnHideWithCustomCondition, + clearOnHideWithHiddenParent, + skipValidForLogicallyHiddenComp, + skipValidForConditionallyHiddenComp, + skipValidWithHiddenParentComp, + forDataGridRequired, + data1a, + form1, + subs, +}; diff --git a/src/process/__tests__/fixtures/skipValidForConditionallyHiddenComp.json b/src/process/__tests__/fixtures/skipValidForConditionallyHiddenComp.json index 0812334e..c84e9e92 100644 --- a/src/process/__tests__/fixtures/skipValidForConditionallyHiddenComp.json +++ b/src/process/__tests__/fixtures/skipValidForConditionallyHiddenComp.json @@ -64,4 +64,4 @@ "submit": true } } -} \ No newline at end of file +} diff --git a/src/process/__tests__/fixtures/skipValidForLogicallyHiddenComp.json b/src/process/__tests__/fixtures/skipValidForLogicallyHiddenComp.json index ee9a887b..a95ca429 100644 --- a/src/process/__tests__/fixtures/skipValidForLogicallyHiddenComp.json +++ b/src/process/__tests__/fixtures/skipValidForLogicallyHiddenComp.json @@ -83,4 +83,3 @@ } } } - diff --git a/src/process/__tests__/fixtures/subs.json b/src/process/__tests__/fixtures/subs.json index b927f139..1c49fff8 100644 --- a/src/process/__tests__/fixtures/subs.json +++ b/src/process/__tests__/fixtures/subs.json @@ -1,152 +1,152 @@ [ - { - "_id": "6570852c1c5d0de6f55de6ae", - "form": "657085141c5d0de6f55de4b7", - "owner": "650a5bfdb9ac8160c0968e59", - "roles": [ ], - "access": [ ], - "metadata": { - "timezone": "America/Chicago", - "offset": -360, + { + "_id": "6570852c1c5d0de6f55de6ae", + "form": "657085141c5d0de6f55de4b7", + "owner": "650a5bfdb9ac8160c0968e59", + "roles": [], + "access": [], + "metadata": { + "timezone": "America/Chicago", + "offset": -360, + "origin": "https://form.local", + "referrer": "", + "browserName": "Netscape", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", + "pathName": "/", + "onLine": true, + "headers": { + "host": "form.local", + "x-real-ip": "172.18.0.1", + "x-forwarded-for": "172.18.0.1", + "x-forwarded-proto": "https", + "connection": "close", + "content-length": "374", + "sec-ch-ua": "\"Brave\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"", + "accept": "application/json", + "content-type": "application/json", + "sec-ch-ua-mobile": "?0", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", + "sec-ch-ua-platform": "\"macOS\"", + "sec-gpc": "1", + "accept-language": "en-US,en;q=0.5", "origin": "https://form.local", - "referrer": "", - "browserName": "Netscape", - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", - "pathName": "/", - "onLine": true, - "headers": { - "host": "form.local", - "x-real-ip": "172.18.0.1", - "x-forwarded-for": "172.18.0.1", - "x-forwarded-proto": "https", - "connection": "close", - "content-length": "374", - "sec-ch-ua": "\"Brave\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"", - "accept": "application/json", - "content-type": "application/json", - "sec-ch-ua-mobile": "?0", - "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", - "sec-ch-ua-platform": "\"macOS\"", - "sec-gpc": "1", - "accept-language": "en-US,en;q=0.5", - "origin": "https://form.local", - "sec-fetch-site": "same-origin", - "sec-fetch-mode": "cors", - "sec-fetch-dest": "empty", - "referer": "https://form.local/", - "accept-encoding": "gzip, deflate, br" - } - }, - "data": { - "name": "C", - "sku": "C", - "price": 30 - }, - "_fvid": 0, - "project": "651185882e5eae71be60b314", - "state": "submitted", - "externalIds": [ ], - "created": "2023-12-06T14:29:00.345Z", - "modified": "2023-12-06T14:29:00.345Z" + "sec-fetch-site": "same-origin", + "sec-fetch-mode": "cors", + "sec-fetch-dest": "empty", + "referer": "https://form.local/", + "accept-encoding": "gzip, deflate, br" + } }, - { - "_id": "657085261c5d0de6f55de612", - "form": "657085141c5d0de6f55de4b7", - "owner": "650a5bfdb9ac8160c0968e59", - "roles": [ ], - "access": [ ], - "metadata": { - "timezone": "America/Chicago", - "offset": -360, + "data": { + "name": "C", + "sku": "C", + "price": 30 + }, + "_fvid": 0, + "project": "651185882e5eae71be60b314", + "state": "submitted", + "externalIds": [], + "created": "2023-12-06T14:29:00.345Z", + "modified": "2023-12-06T14:29:00.345Z" + }, + { + "_id": "657085261c5d0de6f55de612", + "form": "657085141c5d0de6f55de4b7", + "owner": "650a5bfdb9ac8160c0968e59", + "roles": [], + "access": [], + "metadata": { + "timezone": "America/Chicago", + "offset": -360, + "origin": "https://form.local", + "referrer": "", + "browserName": "Netscape", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", + "pathName": "/", + "onLine": true, + "headers": { + "host": "form.local", + "x-real-ip": "172.18.0.1", + "x-forwarded-for": "172.18.0.1", + "x-forwarded-proto": "https", + "connection": "close", + "content-length": "374", + "sec-ch-ua": "\"Brave\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"", + "accept": "application/json", + "content-type": "application/json", + "sec-ch-ua-mobile": "?0", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", + "sec-ch-ua-platform": "\"macOS\"", + "sec-gpc": "1", + "accept-language": "en-US,en;q=0.5", "origin": "https://form.local", - "referrer": "", - "browserName": "Netscape", - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", - "pathName": "/", - "onLine": true, - "headers": { - "host": "form.local", - "x-real-ip": "172.18.0.1", - "x-forwarded-for": "172.18.0.1", - "x-forwarded-proto": "https", - "connection": "close", - "content-length": "374", - "sec-ch-ua": "\"Brave\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"", - "accept": "application/json", - "content-type": "application/json", - "sec-ch-ua-mobile": "?0", - "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", - "sec-ch-ua-platform": "\"macOS\"", - "sec-gpc": "1", - "accept-language": "en-US,en;q=0.5", - "origin": "https://form.local", - "sec-fetch-site": "same-origin", - "sec-fetch-mode": "cors", - "sec-fetch-dest": "empty", - "referer": "https://form.local/", - "accept-encoding": "gzip, deflate, br" - } - }, - "data": { - "name": "B", - "sku": "B", - "price": 20 - }, - "_fvid": 0, - "project": "651185882e5eae71be60b314", - "state": "submitted", - "externalIds": [ ], - "created": "2023-12-06T14:28:54.747Z", - "modified": "2023-12-06T14:28:54.748Z" + "sec-fetch-site": "same-origin", + "sec-fetch-mode": "cors", + "sec-fetch-dest": "empty", + "referer": "https://form.local/", + "accept-encoding": "gzip, deflate, br" + } + }, + "data": { + "name": "B", + "sku": "B", + "price": 20 }, - { - "_id": "6570851e1c5d0de6f55de576", - "form": "657085141c5d0de6f55de4b7", - "owner": "650a5bfdb9ac8160c0968e59", - "roles": [ ], - "access": [ ], - "metadata": { - "timezone": "America/Chicago", - "offset": -360, + "_fvid": 0, + "project": "651185882e5eae71be60b314", + "state": "submitted", + "externalIds": [], + "created": "2023-12-06T14:28:54.747Z", + "modified": "2023-12-06T14:28:54.748Z" + }, + { + "_id": "6570851e1c5d0de6f55de576", + "form": "657085141c5d0de6f55de4b7", + "owner": "650a5bfdb9ac8160c0968e59", + "roles": [], + "access": [], + "metadata": { + "timezone": "America/Chicago", + "offset": -360, + "origin": "https://form.local", + "referrer": "", + "browserName": "Netscape", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", + "pathName": "/", + "onLine": true, + "headers": { + "host": "form.local", + "x-real-ip": "172.18.0.1", + "x-forwarded-for": "172.18.0.1", + "x-forwarded-proto": "https", + "connection": "close", + "content-length": "374", + "sec-ch-ua": "\"Brave\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"", + "accept": "application/json", + "content-type": "application/json", + "sec-ch-ua-mobile": "?0", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", + "sec-ch-ua-platform": "\"macOS\"", + "sec-gpc": "1", + "accept-language": "en-US,en;q=0.5", "origin": "https://form.local", - "referrer": "", - "browserName": "Netscape", - "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", - "pathName": "/", - "onLine": true, - "headers": { - "host": "form.local", - "x-real-ip": "172.18.0.1", - "x-forwarded-for": "172.18.0.1", - "x-forwarded-proto": "https", - "connection": "close", - "content-length": "374", - "sec-ch-ua": "\"Brave\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"", - "accept": "application/json", - "content-type": "application/json", - "sec-ch-ua-mobile": "?0", - "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", - "sec-ch-ua-platform": "\"macOS\"", - "sec-gpc": "1", - "accept-language": "en-US,en;q=0.5", - "origin": "https://form.local", - "sec-fetch-site": "same-origin", - "sec-fetch-mode": "cors", - "sec-fetch-dest": "empty", - "referer": "https://form.local/", - "accept-encoding": "gzip, deflate, br" - } - }, - "data": { - "name": "A", - "sku": "A", - "price": 10 - }, - "_fvid": 0, - "project": "651185882e5eae71be60b314", - "state": "submitted", - "externalIds": [ ], - "created": "2023-12-06T14:28:46.759Z", - "modified": "2023-12-06T14:28:46.760Z" - } - ] \ No newline at end of file + "sec-fetch-site": "same-origin", + "sec-fetch-mode": "cors", + "sec-fetch-dest": "empty", + "referer": "https://form.local/", + "accept-encoding": "gzip, deflate, br" + } + }, + "data": { + "name": "A", + "sku": "A", + "price": 10 + }, + "_fvid": 0, + "project": "651185882e5eae71be60b314", + "state": "submitted", + "externalIds": [], + "created": "2023-12-06T14:28:46.759Z", + "modified": "2023-12-06T14:28:46.760Z" + } +] diff --git a/src/process/__tests__/fixtures/util.ts b/src/process/__tests__/fixtures/util.ts index 53aa54c5..2e7eda8c 100644 --- a/src/process/__tests__/fixtures/util.ts +++ b/src/process/__tests__/fixtures/util.ts @@ -1,12 +1,15 @@ import { get } from 'lodash'; import { ProcessorContext, Component } from 'types'; -export const generateProcessorContext = (component: Component, data: any): ProcessorContext => { - return { - component, - path: component.key, - data, - row: data, - scope: {} as ProcessorScope, - value: get(data, component.key), - } -} +export const generateProcessorContext = ( + component: Component, + data: any, +): ProcessorContext => { + return { + component, + path: component.key, + data, + row: data, + scope: {} as ProcessorScope, + value: get(data, component.key), + }; +}; diff --git a/src/process/__tests__/process.test.ts b/src/process/__tests__/process.test.ts index 6a3e4779..21540ea1 100644 --- a/src/process/__tests__/process.test.ts +++ b/src/process/__tests__/process.test.ts @@ -1,10 +1,19 @@ import { expect } from 'chai'; -import assert from 'node:assert' -import type { ContainerComponent, ProcessContext, ProcessorScope, ValidationScope } from 'types'; +import assert from 'node:assert'; +import type { ContainerComponent, ValidationScope } from 'types'; import { getComponent } from 'utils/formUtil'; import { process, processSync, ProcessTargets } from '../index'; import { fastCloneDeep } from 'utils'; -import { addressComponentWithOtherCondComponents, addressComponentWithOtherCondComponents2, clearOnHideWithCustomCondition, clearOnHideWithHiddenParent, forDataGridRequired, skipValidForConditionallyHiddenComp, skipValidForLogicallyHiddenComp, skipValidWithHiddenParentComp } from './fixtures' +import { + addressComponentWithOtherCondComponents, + addressComponentWithOtherCondComponents2, + clearOnHideWithCustomCondition, + clearOnHideWithHiddenParent, + forDataGridRequired, + skipValidForConditionallyHiddenComp, + skipValidForLogicallyHiddenComp, + skipValidWithHiddenParentComp, +} from './fixtures'; /* describe('Process Tests', () => { @@ -68,8 +77,8 @@ describe('Process Tests', () => { }); */ -describe('Process Tests', () => { - it('Should submit data within a nested form.', async () => { +describe('Process Tests', function () { + it('Should submit data within a nested form.', async function () { const form = { _id: {}, title: 'parent-fio-8023', @@ -425,8 +434,7 @@ describe('Process Tests', () => { key: 'address1', type: 'textfield', input: true, - customConditional: - "show = _.get(instance, 'parent.manualMode', false);", + customConditional: "show = _.get(instance, 'parent.manualMode', false);", }, { label: 'Address 2', @@ -434,8 +442,7 @@ describe('Process Tests', () => { key: 'address2', type: 'textfield', input: true, - customConditional: - "show = _.get(instance, 'parent.manualMode', false);", + customConditional: "show = _.get(instance, 'parent.manualMode', false);", }, { label: 'City', @@ -443,8 +450,7 @@ describe('Process Tests', () => { key: 'city', type: 'textfield', input: true, - customConditional: - "show = _.get(instance, 'parent.manualMode', false);", + customConditional: "show = _.get(instance, 'parent.manualMode', false);", }, { label: 'State', @@ -452,8 +458,7 @@ describe('Process Tests', () => { key: 'state', type: 'textfield', input: true, - customConditional: - "show = _.get(instance, 'parent.manualMode', false);", + customConditional: "show = _.get(instance, 'parent.manualMode', false);", }, { label: 'Country', @@ -461,8 +466,7 @@ describe('Process Tests', () => { key: 'country', type: 'textfield', input: true, - customConditional: - "show = _.get(instance, 'parent.manualMode', false);", + customConditional: "show = _.get(instance, 'parent.manualMode', false);", }, { label: 'Zip Code', @@ -470,8 +474,7 @@ describe('Process Tests', () => { key: 'zip', type: 'textfield', input: true, - customConditional: - "show = _.get(instance, 'parent.manualMode', false);", + customConditional: "show = _.get(instance, 'parent.manualMode', false);", }, ], }, @@ -832,7 +835,6 @@ describe('Process Tests', () => { 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36', pathName: '/', onLine: true, - }, data: { number: 23, @@ -1044,7 +1046,7 @@ describe('Process Tests', () => { expect(context.data.child.data).to.not.have.property('invalid'); }); - it('Should process nested form data correctly', async () => { + it('Should process nested form data correctly', async function () { const submission = { data: { submit: true, @@ -1128,7 +1130,7 @@ describe('Process Tests', () => { expect(context.data.child.data.output).to.equal(20); }); - it('Should process nested data correctly.', async () => { + it('Should process nested data correctly.', async function () { const form = { _id: {}, title: 'parent', @@ -1330,7 +1332,7 @@ describe('Process Tests', () => { }); }); - it('Should allow the submission to go through if the subform is conditionally hidden', async () => { + it('Should allow the submission to go through if the subform is conditionally hidden', async function () { const form = { _id: {}, title: 'parent', @@ -1512,10 +1514,7 @@ describe('Process Tests', () => { assert.equal(context.data.showA, false); assert.equal(context.data.showB, true); assert.equal(context.data.showC, true); - assert( - !context.data.hasOwnProperty('childA'), - 'The childA form should not be present.' - ); + assert(!context.data.hasOwnProperty('childA'), 'The childA form should not be present.'); assert.deepEqual(context.data.childB.data, { c: 'Three', d: 'Four', @@ -1527,7 +1526,7 @@ describe('Process Tests', () => { }); // TODO: test case naming - it('Should not unset submission data of nested forms with identical keys', () => { + it('Should not unset submission data of nested forms with identical keys', function () { const parentForm = { display: 'form', tags: [], @@ -1620,8 +1619,8 @@ describe('Process Tests', () => { data: { a: 'foo', b: 'bar', - } - } + }, + }, }, }, childB: { @@ -1630,8 +1629,8 @@ describe('Process Tests', () => { data: { a: 'baz', b: 'biz', - } - } + }, + }, }, }, }, @@ -1653,21 +1652,18 @@ describe('Process Tests', () => { context.processors = ProcessTargets.evaluator; processSync(context); assert.equal(context.data.showA, false); - assert( - !context.data.hasOwnProperty('childA'), - 'The childA form should not be present.' - ); + assert(!context.data.hasOwnProperty('childA'), 'The childA form should not be present.'); assert.deepEqual(context.data.childB.data, { grandchild: { data: { a: 'baz', b: 'biz', - } - } + }, + }, }); }); - it('Should process data within a fieldset properly.', async () => { + it('Should process data within a fieldset properly.', async function () { const submission = { data: { firstName: 'Joe', @@ -1711,7 +1707,7 @@ describe('Process Tests', () => { expect(context.data.lastName).to.equal('Smith'); }); - it('Requires a conditionally visible field', async () => { + it('Requires a conditionally visible field', async function () { const form = { components: [ { @@ -1797,7 +1793,7 @@ describe('Process Tests', () => { assert.equal(context.scope.errors[0].context.path, 'requiredField'); }); - it("Doesn't require a conditionally hidden field", async () => { + it("Doesn't require a conditionally hidden field", async function () { const form = { components: [ { @@ -1886,7 +1882,7 @@ describe('Process Tests', () => { assert.equal(context.scope.errors.length, 0); }); - it('Allows a conditionally required field', async () => { + it('Allows a conditionally required field', async function () { const form = { components: [ { @@ -1976,7 +1972,7 @@ describe('Process Tests', () => { assert.equal(context.scope.errors.length, 0); }); - it('Ignores conditionally hidden fields', async () => { + it('Ignores conditionally hidden fields', async function () { const form = { components: [ { @@ -2067,7 +2063,7 @@ describe('Process Tests', () => { assert.equal(context.scope.errors.length, 0); }); - it('Requires a conditionally visible field in a panel', async () => { + it('Requires a conditionally visible field in a panel', async function () { const form = { components: [ { @@ -2172,7 +2168,7 @@ describe('Process Tests', () => { assert.equal(context.scope.errors[0].context.path, 'requiredField'); }); - it("Doesn't require a conditionally hidden field in a panel", async () => { + it("Doesn't require a conditionally hidden field in a panel", async function () { const form = { components: [ { @@ -2275,7 +2271,7 @@ describe('Process Tests', () => { assert.equal(context.scope.errors.length, 0); }); - it('Allows a conditionally required field in a panel', async () => { + it('Allows a conditionally required field in a panel', async function () { const form = { components: [ { @@ -2379,7 +2375,7 @@ describe('Process Tests', () => { assert.equal(context.scope.errors.length, 0); }); - it('Should ignore conditionally hidden fields in a panel during validation', async () => { + it('Should ignore conditionally hidden fields in a panel during validation', async function () { const form = { components: [ { @@ -2484,7 +2480,7 @@ describe('Process Tests', () => { assert.equal(context.scope.errors.length, 0); }); - it('Should not include submission data for conditionally hidden fields', async () => { + it('Should not include submission data for conditionally hidden fields', async function () { const form = { display: 'form', components: [ @@ -2535,7 +2531,7 @@ describe('Process Tests', () => { expect(context.data).to.deep.equal({ textField: '' }); }); - it('Should not include submission data for logically hidden fields', async () => { + it('Should not include submission data for logically hidden fields', async function () { const form = { display: 'form', components: [ @@ -2606,7 +2602,7 @@ describe('Process Tests', () => { expect(context.data).to.deep.equal({ textField: '' }); }); - it('Should allow conditionally hidden text fields within DataGrid and EditGrids', async () => { + it('Should allow conditionally hidden text fields within DataGrid and EditGrids', async function () { const form = { display: 'form', components: [ @@ -2710,7 +2706,7 @@ describe('Process Tests', () => { }); }); - it('Should allow conditionally hidden components that depend on state outside of the contextual row data', async () => { + it('Should allow conditionally hidden components that depend on state outside of the contextual row data', async function () { const form = { display: 'form', components: [ @@ -2808,7 +2804,7 @@ describe('Process Tests', () => { }); }); - it('Should allow conditionally hidden components that depend on state outside of the contextual row data with nested structures', async () => { + it('Should allow conditionally hidden components that depend on state outside of the contextual row data with nested structures', async function () { const form = { display: 'form', components: [ @@ -2837,7 +2833,7 @@ describe('Process Tests', () => { input: true, }, ], - input: true + input: true, }, { label: 'Edit Grid', @@ -2917,7 +2913,7 @@ describe('Process Tests', () => { }); }); - it('Should allow conditionally hidden components that depend on state outside of the contextual row data, with co-located component keys in the row that are not targets of conditions', async () => { + it('Should allow conditionally hidden components that depend on state outside of the contextual row data, with co-located component keys in the row that are not targets of conditions', async function () { const form = { display: 'form', components: [ @@ -2989,7 +2985,7 @@ describe('Process Tests', () => { type: 'select', input: true, }, - ] + ], }, { type: 'button', @@ -3008,7 +3004,7 @@ describe('Process Tests', () => { editGrid: [ { textField: 'TEST', - select: 'action1' + select: 'action1', }, ], }, @@ -3031,13 +3027,13 @@ describe('Process Tests', () => { editGrid: [ { textField: 'TEST', - select: 'action1' + select: 'action1', }, ], }); }); - it('Should allow conditionally hidden components that depend on state outside of the contextual row data, with nested and co-located component keys in the row that are not targets of conditions', async () => { + it('Should allow conditionally hidden components that depend on state outside of the contextual row data, with nested and co-located component keys in the row that are not targets of conditions', async function () { const form = { display: 'form', components: [ @@ -3114,7 +3110,7 @@ describe('Process Tests', () => { type: 'select', input: true, }, - ] + ], }, ], }, @@ -3136,10 +3132,10 @@ describe('Process Tests', () => { editGrid: [ { textField: 'TEST', - select: 'action1' + select: 'action1', }, ], - } + }, }, }; @@ -3161,14 +3157,14 @@ describe('Process Tests', () => { editGrid: [ { textField: 'TEST', - select: 'action1' + select: 'action1', }, ], - } + }, }); }); - it('Should include submission data for logically visible fields', async () => { + it('Should include submission data for logically visible fields', async function () { const form = { display: 'form', components: [ @@ -3237,46 +3233,48 @@ describe('Process Tests', () => { }, }; processSync(context); - expect((context.scope as any).conditionals).to.deep.equal([{ - path: 'textArea', - conditionallyHidden: false, - }]); + expect((context.scope as any).conditionals).to.deep.equal([ + { + path: 'textArea', + conditionallyHidden: false, + }, + ]); expect(context.data).to.deep.equal({ textArea: 'should be conditionally visible', textField: 'not empty', }); }); - it('Should not filter a simple datamap compoennt', async () => { + it('Should not filter a simple datamap compoennt', async function () { const form = { display: 'form', components: [ { - label: "Data Map", + label: 'Data Map', tableView: false, validateWhenHidden: false, - key: "dataMap", - type: "datamap", - path: "dataMap", + key: 'dataMap', + type: 'datamap', + path: 'dataMap', input: true, valueComponent: { - type: "textfield", - key: "value", - label: "Value", + type: 'textfield', + key: 'value', + label: 'Value', input: true, hideLabel: true, tableView: true, }, - } - ] + }, + ], }; const submission = { data: { dataMap: { - key1: "value1", - key2: "value2" - } - } + key1: 'value1', + key2: 'value2', + }, + }, }; const context = { form, @@ -3292,14 +3290,14 @@ describe('Process Tests', () => { processSync(context); expect(context.data).to.deep.equal({ dataMap: { - key1: "value1", - key2: "value2" - } + key1: 'value1', + key2: 'value2', + }, }); - }) + }); - it('Should allow the submission to go through without errors if there is no the subform reference value', async () => { - const form = { + it('Should allow the submission to go through without errors if there is no the subform reference value', async function () { + const form = { _id: '66bc5cff7ca1729623a182db', title: 'form2', name: 'form2', @@ -3392,11 +3390,11 @@ describe('Process Tests', () => { context.processors = ProcessTargets.evaluator; processSync(context); assert.equal(context.scope.errors.length, 0); - assert.deepEqual(context.data.form, { _id: '66c455fc0f00757fd4b0e79b', data: {} }) + assert.deepEqual(context.data.form, { _id: '66c455fc0f00757fd4b0e79b', data: {} }); }); - it('Should not hide other components data from submission when address component is filled out', async () => { - const {form, submission} = addressComponentWithOtherCondComponents + it('Should not hide other components data from submission when address component is filled out', async function () { + const { form, submission } = addressComponentWithOtherCondComponents; const errors: any = []; const context = { form, @@ -3417,8 +3415,8 @@ describe('Process Tests', () => { expect(context.submission.data.textField).to.be.equal('some text'); }); - it('Should not hide other components data from submission when address component is not filled out and manual mode enabled', async () => { - const {form, submission} = addressComponentWithOtherCondComponents2 + it('Should not hide other components data from submission when address component is not filled out and manual mode enabled', async function () { + const { form, submission } = addressComponentWithOtherCondComponents2; const errors: any = []; const context = { form, @@ -3439,8 +3437,8 @@ describe('Process Tests', () => { expect(context.submission.data.number2).to.be.equal(2); }); - it('Should not return validation error for multiple textarea with json data type when first value is array', async () => { - const form = { + it('Should not return validation error for multiple textarea with json data type when first value is array', async function () { + const form = { _id: '66f676f14b77db82b230a201', title: 'teterter', name: 'teterter', @@ -3511,7 +3509,7 @@ describe('Process Tests', () => { assert.equal(context.scope.errors.length, 0); }); -it('Should not unset values for conditionally visible fields with different formats of condtion based on selectboxes value', async () => { + it('Should not unset values for conditionally visible fields with different formats of condtion based on selectboxes value', async function () { const form = { _id: '66ffa92ac25689df8702f283', title: 'cond NEW', @@ -3621,15 +3619,15 @@ it('Should not unset values for conditionally visible fields with different form input: true, saveOnEnter: false, }, - ] + ], }; - const data= { + const data = { textField: 'correct condition', textFieldNewWrong: 'new condition with wrong format', textFieldOldFormat: 'legacy condtion', container: { selectBoxes: { a: true, b: false, c: false } }, submit: true, - } + }; const submission = { data: fastCloneDeep(data), @@ -3653,11 +3651,13 @@ it('Should not unset values for conditionally visible fields with different form submission.data = context.data; context.processors = ProcessTargets.evaluator; processSync(context); - (context.scope as any).conditionals.forEach((v: any) => assert.equal(v.conditionallyHidden, false)) + (context.scope as any).conditionals.forEach((v: any) => + assert.equal(v.conditionallyHidden, false), + ); assert.deepEqual(context.data, data); }); - it('Should not return error for the form with conditionals based on the Day component', () => { + it('Should not return error for the form with conditionals based on the Day component', function () { const form = { _id: '66ffe59b598a729e707869bf', title: '9143 condition day', @@ -3674,19 +3674,19 @@ it('Should not unset values for conditionally visible fields with different form tableView: false, fields: { day: { - hide: false + hide: false, }, month: { - hide: false + hide: false, }, year: { - hide: false - } + hide: false, + }, }, validateWhenHidden: false, key: 'day', type: 'day', - input: true + input: true, }, { label: 'Text Field', @@ -3701,12 +3701,12 @@ it('Should not unset values for conditionally visible fields with different form { component: 'day', operator: 'isDateEqual', - value: '09/26/2024' - } - ] + value: '09/26/2024', + }, + ], }, type: 'textfield', - input: true + input: true, }, { type: 'button', @@ -3714,13 +3714,13 @@ it('Should not unset values for conditionally visible fields with different form key: 'submit', disableOnInvalid: true, input: true, - tableView: false - } + tableView: false, + }, ], project: '63cead09be0090345b109e22', created: '2024-10-04T12:54:51.161Z', modified: '2024-10-07T07:47:25.189Z', - machineName: 'idwqwhclwioyqbw:9143ConditionDay' + machineName: 'idwqwhclwioyqbw:9143ConditionDay', }; const submission = { @@ -3729,11 +3729,11 @@ it('Should not unset values for conditionally visible fields with different form data: { day: '09/26/2024', submit: true, - textField: 'test' + textField: 'test', }, _id: '6703a011275ca049014f7fab', project: '63cead09be0090345b109e22', - state: 'submitted' + state: 'submitted', }; const errors: any = []; @@ -3755,11 +3755,11 @@ it('Should not unset values for conditionally visible fields with different form context.processors = ProcessTargets.evaluator; processSync(context); expect(context.scope.conditionals).to.have.length(1); - expect(context.scope.conditionals?.[0].conditionallyHidden).to.be.false; + expect(context.scope.conditionals?.[0].conditionallyHidden).to.equal(false); assert.equal(context.scope.errors.length, 0); }); - it('Should not unset value of the component inside fieldset inside wizard', () => { + it('Should not unset value of the component inside fieldset inside wizard', function () { const form = { _id: '67063bc6094b45c5f33ade96', title: '8802newOne', @@ -3904,13 +3904,13 @@ it('Should not unset values for conditionally visible fields with different form submission.data = context.data; context.processors = ProcessTargets.evaluator; processSync(context); - assert.deepEqual(context.data, { textField: '', textAreaFieldSet: 'test' }) + assert.deepEqual(context.data, { textField: '', textAreaFieldSet: 'test' }); context.scope.conditionals.forEach((cond: any) => { - expect(cond.conditionallyHidden).to.be.true; - }) + expect(cond.conditionallyHidden).to.be.equal(true); + }); }); - describe('Required component validation in nested form in DataGrid/EditGrid', () => { + describe('Required component validation in nested form in DataGrid/EditGrid', function () { const nestedForm = { key: 'form', type: 'form', @@ -3927,7 +3927,7 @@ it('Should not unset values for conditionally visible fields with different form ], }; - describe('For DataGrid:', () => { + describe('For DataGrid:', function () { const components = [ { key: 'dataGrid', @@ -3936,7 +3936,8 @@ it('Should not unset values for conditionally visible fields with different form components: [nestedForm], }, ]; - it('Should validate required component when it is filled out', async () => { + + it('Should validate required component when it is filled out', async function () { const submission = { data: { dataGrid: [ @@ -3969,14 +3970,13 @@ it('Should not unset values for conditionally visible fields with different form processSync(context); context.processors = ProcessTargets.evaluator; processSync(context); - const errors = (context.scope as ValidationScope).errors; expect(context.data).to.deep.equal({ dataGrid: [{ form: { data: { textField: 'test' } } }], }); expect((context.scope as ValidationScope).errors).to.have.length(0); - expect; }); - it('Should not validate required component when it is not filled out', async () => { + + it('Should not validate required component when it is not filled out', async function () { const submission = { data: { dataGrid: [ @@ -4009,7 +4009,7 @@ it('Should not unset values for conditionally visible fields with different form }); }); - it('Should not return fields from conditionally hidden containers, clearOnHide = true', async () => { + it('Should not return fields from conditionally hidden containers, clearOnHide = true', async function () { const { form, submission } = clearOnHideWithCustomCondition; const context = { form, @@ -4028,12 +4028,12 @@ it('Should not unset values for conditionally visible fields with different form processSync(context); expect(context.data).to.deep.equal({ - candidates:[{candidate:{data:{}}}], - submit: true + candidates: [{ candidate: { data: {} } }], + submit: true, }); }); - it('Should skip child validation with conditional', async () => { + it('Should skip child validation with conditional', async function () { const { form, submission } = skipValidForConditionallyHiddenComp; const context = { form, @@ -4053,7 +4053,7 @@ it('Should not unset values for conditionally visible fields with different form expect((context.scope as ValidationScope).errors).to.have.length(0); }); - it('Should skip child validation with hidden parent component', async () => { + it('Should skip child validation with hidden parent component', async function () { const { form, submission } = skipValidWithHiddenParentComp; const context = { form, @@ -4073,7 +4073,7 @@ it('Should not unset values for conditionally visible fields with different form expect((context.scope as ValidationScope).errors).to.have.length(0); }); - it('Should skip child validation with logic', async () => { + it('Should skip child validation with logic', async function () { const { form, submission } = skipValidForLogicallyHiddenComp; const context = { form, @@ -4093,7 +4093,7 @@ it('Should not unset values for conditionally visible fields with different form expect((context.scope as ValidationScope).errors).to.have.length(0); }); - it('Should not return fields from conditionally hidden containers, clearOnHide = false', async () => { + it('Should not return fields from conditionally hidden containers, clearOnHide = false', async function () { const { form, submission } = clearOnHideWithCustomCondition; const containerComponent = getComponent(form.components, 'section6') as ContainerComponent; containerComponent.clearOnHide = false; @@ -4114,12 +4114,12 @@ it('Should not unset values for conditionally visible fields with different form processSync(context); expect(context.data).to.deep.equal({ - candidates:[{candidate:{data:{section6:{}}}}], - submit: true + candidates: [{ candidate: { data: { section6: {} } } }], + submit: true, }); }); - it('Should not validate fields from hidden containers, clearOnHide = false', async () => { + it('Should not validate fields from hidden containers, clearOnHide = false', async function () { const { form, submission } = clearOnHideWithHiddenParent; const context = { form, @@ -4127,7 +4127,7 @@ it('Should not unset values for conditionally visible fields with different form data: submission.data, components: form.components, processors: ProcessTargets.submission, - scope: { errors: []}, + scope: { errors: [] }, config: { server: true, }, @@ -4138,13 +4138,13 @@ it('Should not unset values for conditionally visible fields with different form processSync(context); expect(context.data).to.deep.equal({ - candidates:[{candidate:{data:{section6:{}}}}], - submit: true + candidates: [{ candidate: { data: { section6: {} } } }], + submit: true, }); expect(context.scope.errors.length).to.equal(0); }); - it('Should not return fields from hidden containers, clearOnHide = true', async () => { + it('Should not return fields from hidden containers, clearOnHide = true', async function () { const { form, submission } = clearOnHideWithHiddenParent; const containerComponent = getComponent(form.components, 'section6') as ContainerComponent; containerComponent.clearOnHide = true; @@ -4165,12 +4165,12 @@ it('Should not unset values for conditionally visible fields with different form processSync(context); expect(context.data).to.deep.equal({ - candidates:[{candidate:{data:{}}}], - submit: true + candidates: [{ candidate: { data: {} } }], + submit: true, }); }); - it('Should validate when all child components are empty in required Data Grid', async () => { + it('Should validate when all child components are empty in required Data Grid', async function () { const { form, submission } = forDataGridRequired; const context = { form, @@ -4191,8 +4191,8 @@ it('Should not unset values for conditionally visible fields with different form expect((context.scope as ValidationScope).errors).to.have.length(1); }); - it('Should validate required an empty array for multiple select', async () => { - const form = { + it('Should validate required an empty array for multiple select', async function () { + const form = { _id: '66f4141e34ac6c4049cc5144', title: 'required multiple', name: 'requiredMultiple', @@ -4272,7 +4272,7 @@ it('Should not unset values for conditionally visible fields with different form assert.equal(context.scope.errors[0].ruleName, 'required'); }); - describe('For EditGrid:', () => { + describe('For EditGrid:', function () { const components = [ { key: 'editGrid', @@ -4281,7 +4281,8 @@ it('Should not unset values for conditionally visible fields with different form components: [nestedForm], }, ]; - it('should return empty array when no data is provided', async () => { + + it('should return empty array when no data is provided', async function () { const submission = { data: { editGrid: [], @@ -4302,9 +4303,9 @@ it('Should not unset values for conditionally visible fields with different form context.processors = ProcessTargets.evaluator; processSync(context); expect(context.data).to.deep.equal({ editGrid: [] }); + }); - }) - it('Should validate required component when it is filled out', async () => { + it('Should validate required component when it is filled out', async function () { const submission = { data: { editGrid: [ @@ -4314,7 +4315,6 @@ it('Should not unset values for conditionally visible fields with different form textField: 'test', invalidField: 'bad', }, - }, }, { @@ -4341,11 +4341,12 @@ it('Should not unset values for conditionally visible fields with different form console.log(JSON.stringify(context.data, null, 2)); expect((context.scope as ValidationScope).errors).to.have.length(0); - expect(context.data).to.deep.equal({ + expect(context.data).to.deep.equal({ editGrid: [{ form: { data: { textField: 'test' } } }], }); }); - it('Should not validate required component when it is not filled out', async () => { + + it('Should not validate required component when it is not filled out', async function () { const submission = { data: { editGrid: [ @@ -4376,7 +4377,6 @@ it('Should not unset values for conditionally visible fields with different form processSync(context); expect((context.scope as ValidationScope).errors).to.have.length(1); }); - }); }); diff --git a/src/process/calculation/__tests__/calculation.test.ts b/src/process/calculation/__tests__/calculation.test.ts index c5a51ca2..d1fdc77b 100644 --- a/src/process/calculation/__tests__/calculation.test.ts +++ b/src/process/calculation/__tests__/calculation.test.ts @@ -1,84 +1,84 @@ import { expect } from 'chai'; -import { process } from '../../process' +import { process } from '../../process'; import { calculateProcessInfo } from '../index'; import { CalculationScope, ProcessContext } from 'types'; const processForm = async (form: any, submission: any) => { - const context: ProcessContext = { - processors: [calculateProcessInfo], - components: form.components, - data: submission.data, - scope: {} - }; - await process(context); - return context; + const context: ProcessContext = { + processors: [calculateProcessInfo], + components: form.components, + data: submission.data, + scope: {}, + }; + await process(context); + return context; }; -describe('Calculation processor', () => { - it('Calculation processor will perform a simple calculation', async () => { - const form = { - components: [ - { - type: 'number', - key: 'a', - input: true - }, - { - type: 'number', - key: 'b', - input: true - }, - { - type: 'number', - key: 'c', - input: true, - calculateValue: 'value = data.a + data.b' - } - ] - }; +describe('Calculation processor', function () { + it('Calculation processor will perform a simple calculation', async function () { + const form = { + components: [ + { + type: 'number', + key: 'a', + input: true, + }, + { + type: 'number', + key: 'b', + input: true, + }, + { + type: 'number', + key: 'c', + input: true, + calculateValue: 'value = data.a + data.b', + }, + ], + }; - const submission = { - data: { - a: 1, - b: 2 - } - }; + const submission = { + data: { + a: 1, + b: 2, + }, + }; - const context: ProcessContext = await processForm(form, submission); - expect(context.data.c).to.equal(3); - }); + const context: ProcessContext = await processForm(form, submission); + expect(context.data.c).to.equal(3); + }); - it('Calculation processor will perform a simple calculation that overwrites the value prop', async () => { - const form = { - components: [ - { - type: 'number', - key: 'a', - input: true - }, - { - type: 'number', - key: 'b', - input: true - }, - { - type: 'number', - key: 'c', - input: true, - calculateValue: 'value = value + data.a + data.b' - } - ] - }; + it('Calculation processor will perform a simple calculation that overwrites the value prop', async function () { + const form = { + components: [ + { + type: 'number', + key: 'a', + input: true, + }, + { + type: 'number', + key: 'b', + input: true, + }, + { + type: 'number', + key: 'c', + input: true, + calculateValue: 'value = value + data.a + data.b', + }, + ], + }; - const submission = { - data: { - a: 1, - b: 2, - c: 3, - } - }; + const submission = { + data: { + a: 1, + b: 2, + c: 3, + }, + }; - const context: ProcessContext = await processForm(form, submission); - expect(context.data.c).to.equal(6); - }); + const context: ProcessContext = await processForm(form, submission); + expect(context.data.c).to.equal(6); + }); }); diff --git a/src/process/calculation/index.ts b/src/process/calculation/index.ts index 349805e7..30d3c6c3 100644 --- a/src/process/calculation/index.ts +++ b/src/process/calculation/index.ts @@ -1,46 +1,53 @@ import { JSONLogicEvaluator } from 'modules/jsonlogic'; -import { ProcessorFn, ProcessorFnSync, CalculationScope, CalculationContext, ProcessorInfo, FilterScope } from 'types'; +import { + ProcessorFn, + ProcessorFnSync, + CalculationScope, + CalculationContext, + ProcessorInfo, +} from 'types'; import { set } from 'lodash'; export const shouldCalculate = (context: CalculationContext): boolean => { - const { component, config } = context; - if ( - !component.calculateValue || - (config?.server && !component.calculateServer) - ) { - return false; - } - return true; + const { component, config } = context; + if (!component.calculateValue || (config?.server && !component.calculateServer)) { + return false; + } + return true; }; -export const calculateProcessSync: ProcessorFnSync = (context: CalculationContext) => { - const { component, data, evalContext, scope, path, value } = context; - if (!shouldCalculate(context)) { - return; - } - const evalContextValue = evalContext ? evalContext(context) : context; - evalContextValue.value = value || null; - if (!scope.calculated) scope.calculated = []; - let newValue = JSONLogicEvaluator.evaluate(component.calculateValue, evalContextValue, 'value'); - - // Only set a new value if it is not "null" which would be the case if no calculation occurred. - if (newValue !== null) { - scope.calculated.push({ - path, - value: newValue - }); - set(data, path, newValue); - } +export const calculateProcessSync: ProcessorFnSync = ( + context: CalculationContext, +) => { + const { component, data, evalContext, scope, path, value } = context; + if (!shouldCalculate(context)) { return; + } + const evalContextValue = evalContext ? evalContext(context) : context; + evalContextValue.value = value || null; + if (!scope.calculated) scope.calculated = []; + const newValue = JSONLogicEvaluator.evaluate(component.calculateValue, evalContextValue, 'value'); + + // Only set a new value if it is not "null" which would be the case if no calculation occurred. + if (newValue !== null) { + scope.calculated.push({ + path, + value: newValue, + }); + set(data, path, newValue); + } + return; }; -export const calculateProcess: ProcessorFn = async (context: CalculationContext) => { - return calculateProcessSync(context); +export const calculateProcess: ProcessorFn = async ( + context: CalculationContext, +) => { + return calculateProcessSync(context); }; export const calculateProcessInfo: ProcessorInfo = { - name: 'calculate', - process: calculateProcess, - processSync: calculateProcessSync, - shouldProcess: shouldCalculate, + name: 'calculate', + process: calculateProcess, + processSync: calculateProcessSync, + shouldProcess: shouldCalculate, }; diff --git a/src/process/clearHidden.ts b/src/process/clearHidden.ts index 39c22b33..ef2054e4 100644 --- a/src/process/clearHidden.ts +++ b/src/process/clearHidden.ts @@ -1,48 +1,52 @@ import { unset } from 'lodash'; import { - ProcessorScope, - ProcessorContext, - ProcessorInfo, - ProcessorFnSync, - ConditionsScope, -} from "types"; + ProcessorScope, + ProcessorContext, + ProcessorInfo, + ProcessorFnSync, + ConditionsScope, +} from 'types'; type ClearHiddenScope = ProcessorScope & { - clearHidden: { - [path: string]: boolean; - } -} + clearHidden: { + [path: string]: boolean; + }; +}; /** * This processor function checks components for the `hidden` property and unsets corresponding data */ export const clearHiddenProcess: ProcessorFnSync = (context) => { - const { component, data, path, value, scope } = context; - - // No need to unset the value if it's undefined - if (value === undefined) { - return; - } - - if (!scope.clearHidden) { - scope.clearHidden = {}; - } - - // 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 path === cond.path && cond.conditionallyHidden; - }); - - const shouldClearValueWhenHidden = !component.hasOwnProperty('clearOnHide') || component.clearOnHide; - - if (shouldClearValueWhenHidden && (isConditionallyHidden || component.hidden || component.ephemeralState?.conditionallyHidden)) { - unset(data, path); - scope.clearHidden[path] = true; - } -} + const { component, data, path, value, scope } = context; + + // No need to unset the value if it's undefined + if (value === undefined) { + return; + } + + if (!scope.clearHidden) { + scope.clearHidden = {}; + } + + // 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 path === cond.path && cond.conditionallyHidden; + }); + + const shouldClearValueWhenHidden = + !component.hasOwnProperty('clearOnHide') || component.clearOnHide; + + if ( + shouldClearValueWhenHidden && + (isConditionallyHidden || component.hidden || component.ephemeralState?.conditionallyHidden) + ) { + unset(data, path); + scope.clearHidden[path] = true; + } +}; export const clearHiddenProcessInfo: ProcessorInfo, void> = { - name: 'clearHidden', - shouldProcess: () => true, - processSync: clearHiddenProcess, -} + name: 'clearHidden', + shouldProcess: () => true, + processSync: clearHiddenProcess, +}; diff --git a/src/process/conditions/__tests__/conditions.test.ts b/src/process/conditions/__tests__/conditions.test.ts index 05467f37..75dd789c 100644 --- a/src/process/conditions/__tests__/conditions.test.ts +++ b/src/process/conditions/__tests__/conditions.test.ts @@ -5,19 +5,19 @@ import { ConditionsScope, ProcessContext } from 'types'; import { get } from 'lodash'; const processForm = (form: any, submission: any) => { - const context: ProcessContext = { - processors: [conditionProcessInfo], - components: form.components, - data: submission.data, - form, - scope: {} - }; - processSync(context); - return context; + const context: ProcessContext = { + processors: [conditionProcessInfo], + components: form.components, + data: submission.data, + form, + scope: {}, + }; + processSync(context); + return context; }; -describe('Condition processor', () => { - it('Should modify component\'s "hidden" property when conditionally visible is false', async () => { +describe('Condition processor', function () { + it('Should modify component\'s "hidden" property when conditionally visible is false', async function () { const form = { components: [ { @@ -49,16 +49,13 @@ describe('Condition processor', () => { }, }; - const context: ProcessContext = processForm( - form, - submission - ); + const context: ProcessContext = processForm(form, submission); expect(context.scope.conditionals).to.have.length(1); expect(context.scope.conditionals?.[0].path).to.equal(form.components[1].key); - expect(context.scope.conditionals?.[0].conditionallyHidden).to.be.true; + expect(context.scope.conditionals?.[0].conditionallyHidden).to.equal(true); }); - it('Should not define a conditional component (that condition is based on selectBoxes value) as hidden', async () => { + it('Should not define a conditional component (that condition is based on selectBoxes value) as hidden', async function () { const form1 = { components: [ { @@ -137,16 +134,12 @@ describe('Condition processor', () => { }, }; - const context: ProcessContext = processForm( - form1, - submission1 - ); + const context: ProcessContext = processForm(form1, submission1); - expect(get(context, 'scope.conditionals[0].conditionallyHidden')).to.be - .false; + expect(get(context, 'scope.conditionals[0].conditionallyHidden')).to.equal(false); }); - it('Should always add components keyed by absolute path to conditional scope (simple components)', async () => { + it('Should always add components keyed by absolute path to conditional scope (simple components)', async function () { const form = { components: [ { @@ -178,15 +171,12 @@ describe('Condition processor', () => { }, }; - const context: ProcessContext = processForm( - form, - submission - ); + const context: ProcessContext = processForm(form, submission); expect(context.scope.conditionals).to.have.length(1); expect(context.scope.conditionals?.[0].path).to.equal('b'); }); - it('Should always add components keyed by absolute data path to conditional scope (data grid components)', async () => { + it('Should always add components keyed by absolute data path to conditional scope (data grid components)', async function () { const form = { components: [ { @@ -253,20 +243,13 @@ describe('Condition processor', () => { }, }; - const context: ProcessContext = processForm( - form, - submission - ); + const context: ProcessContext = processForm(form, submission); expect(context.scope.conditionals).to.have.length(2); - expect(context.scope.conditionals?.[0].path).to.equal( - 'dataGrid[0].textField' - ); - expect(context.scope.conditionals?.[1].path).to.equal( - 'dataGrid[1].textField' - ); + expect(context.scope.conditionals?.[0].path).to.equal('dataGrid[0].textField'); + expect(context.scope.conditionals?.[1].path).to.equal('dataGrid[1].textField'); }); - it('Should always add components keyed by absolute data path to conditional scope (edit grid components)', async () => { + it('Should always add components keyed by absolute data path to conditional scope (edit grid components)', async function () { const form = { components: [ { @@ -333,20 +316,13 @@ describe('Condition processor', () => { }, }; - const context: ProcessContext = processForm( - form, - submission - ); + const context: ProcessContext = processForm(form, submission); expect(context.scope.conditionals).to.have.length(2); - expect(context.scope.conditionals?.[0].path).to.equal( - 'editGrid[0].textField' - ); - expect(context.scope.conditionals?.[1].path).to.equal( - 'editGrid[1].textField' - ); + expect(context.scope.conditionals?.[0].path).to.equal('editGrid[0].textField'); + expect(context.scope.conditionals?.[1].path).to.equal('editGrid[1].textField'); }); - it('Should always add components keyed by absolute data path to conditional scope (container components)', async () => { + it('Should always add components keyed by absolute data path to conditional scope (container components)', async function () { const form = { components: [ { @@ -406,17 +382,12 @@ describe('Condition processor', () => { }, }; - const context: ProcessContext = processForm( - form, - submission - ); + const context: ProcessContext = processForm(form, submission); expect(context.scope.conditionals).to.have.length(1); - expect(context.scope.conditionals?.[0].path).to.equal( - 'container.textField' - ); + expect(context.scope.conditionals?.[0].path).to.equal('container.textField'); }); - it('Should always add components keyed by absolute data path to conditional scope (layout components)', async () => { + it('Should always add components keyed by absolute data path to conditional scope (layout components)', async function () { const form = { components: [ { @@ -476,16 +447,13 @@ describe('Condition processor', () => { }, }; - const context: ProcessContext = processForm( - form, - submission - ); + const context: ProcessContext = processForm(form, submission); expect(context.scope.conditionals).to.have.length(1); // Panel components are layout components, so are not pathed expect(context.scope.conditionals?.[0].path).to.equal('textField'); }); - it('Should always add components keyed by absolute data path to conditional scope (deeply nested components)', async () => { + it('Should always add components keyed by absolute data path to conditional scope (deeply nested components)', async function () { const form = { components: [ { @@ -638,13 +606,10 @@ describe('Condition processor', () => { }, }; - const context: ProcessContext = processForm( - form, - submission - ); + const context: ProcessContext = processForm(form, submission); expect(context.scope.conditionals).to.have.length(1); expect(context.scope.conditionals?.[0].path).to.equal( - 'outerDataGrid[0].outerContainer.innerContainer.innerDataGrid[0].textField' + 'outerDataGrid[0].outerContainer.innerContainer.innerDataGrid[0].textField', ); }); }); diff --git a/src/process/conditions/index.ts b/src/process/conditions/index.ts index fd5337c4..ac24d75f 100644 --- a/src/process/conditions/index.ts +++ b/src/process/conditions/index.ts @@ -1,144 +1,162 @@ -import { ProcessorFn, ProcessorFnSync, ConditionsScope, ProcessorInfo, ConditionsContext, SimpleConditional, JSONConditional, LegacyConditional, SimpleConditionalConditions, Component, NestedComponent, FilterScope } from 'types'; +import { + ProcessorFn, + ProcessorFnSync, + ConditionsScope, + ProcessorInfo, + ConditionsContext, +} from 'types'; import { registerEphemeralState } from 'utils'; import { - checkCustomConditional, - checkJsonConditional, - checkLegacyConditional, - checkSimpleConditional, - isLegacyConditional, - isSimpleConditional, - isJSONConditional + checkCustomConditional, + checkJsonConditional, + checkLegacyConditional, + checkSimpleConditional, + isLegacyConditional, + isSimpleConditional, + isJSONConditional, } from 'utils/conditions'; - const hasCustomConditions = (context: ConditionsContext): boolean => { - const { component } = context; - return !!component.customConditional; -} + const { component } = context; + return !!component.customConditional; +}; const hasSimpleConditions = (context: ConditionsContext): boolean => { - const { component } = context; - const { conditional } = component; - if ( - isLegacyConditional(conditional) || - isSimpleConditional(conditional) || - isJSONConditional(conditional) - ) { - return true; - } - return false; -} + const { component } = context; + const { conditional } = component; + if ( + isLegacyConditional(conditional) || + isSimpleConditional(conditional) || + isJSONConditional(conditional) + ) { + return true; + } + return false; +}; export const hasConditions = (context: ConditionsContext): boolean => { - return hasSimpleConditions(context) || hasCustomConditions(context); + return hasSimpleConditions(context) || hasCustomConditions(context); }; export const isCustomConditionallyHidden = (context: ConditionsContext): boolean => { - if (!hasCustomConditions(context)) { - return false; - } - const { component } = context; - const { customConditional } = component; - let show: boolean | null = null; - if (customConditional) { - show = checkCustomConditional(customConditional, context, 'show'); - } - if (show === null) { - return false; - } - return !show; + if (!hasCustomConditions(context)) { + return false; + } + const { component } = context; + const { customConditional } = component; + let show: boolean | null = null; + if (customConditional) { + show = checkCustomConditional(customConditional, context, 'show'); + } + if (show === null) { + return false; + } + return !show; }; export const isSimpleConditionallyHidden = (context: ConditionsContext): boolean => { - if (!hasSimpleConditions(context)) { - return false; - } - const { component } = context; - const { conditional } = component; - let show: boolean | null = null; - if (isJSONConditional(conditional)) { - show = checkJsonConditional(conditional, context); - } - if (isLegacyConditional(conditional)) { - show = checkLegacyConditional(conditional, context); - } - if (isSimpleConditional(conditional)) { - show = checkSimpleConditional(conditional, context); - } - if (show === null || show === undefined) { - return false; - } - return !show; + if (!hasSimpleConditions(context)) { + return false; + } + const { component } = context; + const { conditional } = component; + let show: boolean | null = null; + if (isJSONConditional(conditional)) { + show = checkJsonConditional(conditional, context); + } + if (isLegacyConditional(conditional)) { + show = checkLegacyConditional(conditional, context); + } + if (isSimpleConditional(conditional)) { + show = checkSimpleConditional(conditional, context); + } + if (show === null || show === undefined) { + return false; + } + return !show; }; export const isConditionallyHidden = (context: ConditionsContext): boolean => { - return isCustomConditionallyHidden(context) || isSimpleConditionallyHidden(context); + return isCustomConditionallyHidden(context) || isSimpleConditionallyHidden(context); }; export type ConditionallyHidden = (context: ConditionsContext) => boolean; export const conditionalProcess = (context: ConditionsContext, isHidden: ConditionallyHidden) => { - const { scope, path } = context; - if (!hasConditions(context)) { - return; - } - - if (!scope.conditionals) { - scope.conditionals = []; - } - let conditionalComp = scope.conditionals.find((cond) => (cond.path === path)); - if (!conditionalComp) { - conditionalComp = {path, conditionallyHidden: false}; - scope.conditionals.push(conditionalComp); - } - - conditionalComp.conditionallyHidden = conditionalComp.conditionallyHidden || isHidden(context) === true; - if (conditionalComp.conditionallyHidden) { - registerEphemeralState(context.component, 'conditionallyHidden', true); - } + const { scope, path } = context; + if (!hasConditions(context)) { + return; + } + + if (!scope.conditionals) { + scope.conditionals = []; + } + let conditionalComp = scope.conditionals.find((cond) => cond.path === path); + if (!conditionalComp) { + conditionalComp = { path, conditionallyHidden: false }; + scope.conditionals.push(conditionalComp); + } + + conditionalComp.conditionallyHidden = + conditionalComp.conditionallyHidden || isHidden(context) === true; + if (conditionalComp.conditionallyHidden) { + registerEphemeralState(context.component, 'conditionallyHidden', true); + } }; -export const customConditionProcess: ProcessorFn = async (context: ConditionsContext) => { - return customConditionProcessSync(context); +export const customConditionProcess: ProcessorFn = async ( + context: ConditionsContext, +) => { + return customConditionProcessSync(context); }; -export const customConditionProcessSync: ProcessorFnSync = (context: ConditionsContext) => { - return conditionalProcess(context, isCustomConditionallyHidden); +export const customConditionProcessSync: ProcessorFnSync = ( + context: ConditionsContext, +) => { + return conditionalProcess(context, isCustomConditionallyHidden); }; -export const simpleConditionProcess: ProcessorFn = async (context: ConditionsContext) => { - return simpleConditionProcessSync(context); +export const simpleConditionProcess: ProcessorFn = async ( + context: ConditionsContext, +) => { + return simpleConditionProcessSync(context); }; -export const simpleConditionProcessSync: ProcessorFnSync = (context: ConditionsContext) => { - return conditionalProcess(context, isSimpleConditionallyHidden); +export const simpleConditionProcessSync: ProcessorFnSync = ( + context: ConditionsContext, +) => { + return conditionalProcess(context, isSimpleConditionallyHidden); }; -export const conditionProcess: ProcessorFn = async (context: ConditionsContext) => { - return conditionProcessSync(context); +export const conditionProcess: ProcessorFn = async ( + context: ConditionsContext, +) => { + return conditionProcessSync(context); }; -export const conditionProcessSync: ProcessorFnSync = (context: ConditionsContext) => { - return conditionalProcess(context, isConditionallyHidden); +export const conditionProcessSync: ProcessorFnSync = ( + context: ConditionsContext, +) => { + return conditionalProcess(context, isConditionallyHidden); }; export const customConditionProcessInfo: ProcessorInfo = { - name: 'customConditions', - process: customConditionProcess, - processSync: customConditionProcessSync, - shouldProcess: hasCustomConditions, + name: 'customConditions', + process: customConditionProcess, + processSync: customConditionProcessSync, + shouldProcess: hasCustomConditions, }; export const simpleConditionProcessInfo: ProcessorInfo = { - name: 'simpleConditions', - process: simpleConditionProcess, - processSync: simpleConditionProcessSync, - shouldProcess: hasSimpleConditions, + name: 'simpleConditions', + process: simpleConditionProcess, + processSync: simpleConditionProcessSync, + shouldProcess: hasSimpleConditions, }; export const conditionProcessInfo: ProcessorInfo = { - name: 'conditions', - process: conditionProcess, - processSync: conditionProcessSync, - shouldProcess: hasSimpleConditions, + name: 'conditions', + process: conditionProcess, + processSync: conditionProcessSync, + shouldProcess: hasSimpleConditions, }; diff --git a/src/process/defaultValue/__tests__/defaultValue.test.ts b/src/process/defaultValue/__tests__/defaultValue.test.ts index 0742a6da..d68b1083 100644 --- a/src/process/defaultValue/__tests__/defaultValue.test.ts +++ b/src/process/defaultValue/__tests__/defaultValue.test.ts @@ -1,20 +1,3 @@ -import { expect } from 'chai'; -import { process } from '../../process' -import { defaultValueProcessInfo } from '../index'; -import { DefaultValueScope, ProcessContext } from 'types'; - -const processForm = async (form: any, submission: any) => { - const context: ProcessContext = { - processors: [defaultValueProcessInfo], - components: form.components, - data: submission.data, - scope: {} - }; - await process(context); - return context; -}; - -describe('Default Value processor', () => { - it('Perform default value processors.', async () => { - }); -}); \ No newline at end of file +describe('Default Value processor', function () { + it('Perform default value processors.', async function () {}); +}); diff --git a/src/process/defaultValue/index.ts b/src/process/defaultValue/index.ts index 60f19a84..8a206f77 100644 --- a/src/process/defaultValue/index.ts +++ b/src/process/defaultValue/index.ts @@ -1,117 +1,136 @@ import { JSONLogicEvaluator } from 'modules/jsonlogic'; -import { ProcessorFn, ProcessorFnSync, ConditionsScope, ProcessorInfo, DefaultValueContext } from 'types'; +import { + ProcessorFn, + ProcessorFnSync, + ConditionsScope, + ProcessorInfo, + DefaultValueContext, +} from 'types'; import { set, has } from 'lodash'; import { getComponentKey } from 'utils/formUtil'; export const hasCustomDefaultValue = (context: DefaultValueContext): boolean => { - const { component } = context; - if (!component.customDefaultValue) { - return false; - } - return true; + const { component } = context; + if (!component.customDefaultValue) { + return false; + } + return true; }; export const hasServerDefaultValue = (context: DefaultValueContext): boolean => { - const { component } = context; - if (!component.hasOwnProperty('defaultValue')) { - return false; - } - return true; + const { component } = context; + if (!component.hasOwnProperty('defaultValue')) { + return false; + } + return true; }; export const hasDefaultValue = (context: DefaultValueContext): boolean => { - return hasCustomDefaultValue(context) || hasServerDefaultValue(context); + return hasCustomDefaultValue(context) || hasServerDefaultValue(context); }; -export const customDefaultValueProcess: ProcessorFn = async (context: DefaultValueContext) => { - return customDefaultValueProcessSync(context); +export const customDefaultValueProcess: ProcessorFn = async ( + context: DefaultValueContext, +) => { + return customDefaultValueProcessSync(context); }; -export const customDefaultValueProcessSync: ProcessorFnSync = (context: DefaultValueContext) => { - const { component, row, data, scope, evalContext, path } = context; - if (!hasCustomDefaultValue(context)) { - return; - } - if (!scope.defaultValues) scope.defaultValues = []; - if (has(row, getComponentKey(component))) { - return; - } - let defaultValue = null; - if (component.customDefaultValue) { - const evalContextValue = evalContext ? evalContext(context) : context; - evalContextValue.value = null; - defaultValue = JSONLogicEvaluator.evaluate(component.customDefaultValue, evalContextValue, 'value'); - if (component.multiple && !Array.isArray(defaultValue)) { - defaultValue = defaultValue ? [defaultValue] : []; - } - scope.defaultValues.push({ - path, - value: defaultValue - }); - } - if (defaultValue !== null && defaultValue !== undefined) { - set(data, path, defaultValue); +export const customDefaultValueProcessSync: ProcessorFnSync = ( + context: DefaultValueContext, +) => { + const { component, row, data, scope, evalContext, path } = context; + if (!hasCustomDefaultValue(context)) { + return; + } + if (!scope.defaultValues) scope.defaultValues = []; + if (has(row, getComponentKey(component))) { + return; + } + let defaultValue = null; + if (component.customDefaultValue) { + const evalContextValue = evalContext ? evalContext(context) : context; + evalContextValue.value = null; + defaultValue = JSONLogicEvaluator.evaluate( + component.customDefaultValue, + evalContextValue, + 'value', + ); + if (component.multiple && !Array.isArray(defaultValue)) { + defaultValue = defaultValue ? [defaultValue] : []; } + scope.defaultValues.push({ + path, + value: defaultValue, + }); + } + if (defaultValue !== null && defaultValue !== undefined) { + set(data, path, defaultValue); + } }; -export const serverDefaultValueProcess: ProcessorFn = async (context: DefaultValueContext) => { - return serverDefaultValueProcessSync(context); +export const serverDefaultValueProcess: ProcessorFn = async ( + context: DefaultValueContext, +) => { + return serverDefaultValueProcessSync(context); }; -export const serverDefaultValueProcessSync: ProcessorFnSync = (context: DefaultValueContext) => { - const { component, row, data, scope, path } = context; - if (!hasServerDefaultValue(context)) { - return; - } - if (!scope.defaultValues) scope.defaultValues = []; - if (has(row, getComponentKey(component))) { - return; - } - let defaultValue = null; - if ( - component.defaultValue !== undefined && - component.defaultValue !== null - ) { - defaultValue = component.defaultValue; - if (component.multiple && !Array.isArray(defaultValue)) { - defaultValue = defaultValue ? [defaultValue] : []; - } - scope.defaultValues.push({ - path, - value: defaultValue - }); - } - if (defaultValue !== null && defaultValue !== undefined) { - set(data, path, defaultValue); +export const serverDefaultValueProcessSync: ProcessorFnSync = ( + context: DefaultValueContext, +) => { + const { component, row, data, scope, path } = context; + if (!hasServerDefaultValue(context)) { + return; + } + if (!scope.defaultValues) scope.defaultValues = []; + if (has(row, getComponentKey(component))) { + return; + } + let defaultValue = null; + if (component.defaultValue !== undefined && component.defaultValue !== null) { + defaultValue = component.defaultValue; + if (component.multiple && !Array.isArray(defaultValue)) { + defaultValue = defaultValue ? [defaultValue] : []; } + scope.defaultValues.push({ + path, + value: defaultValue, + }); + } + if (defaultValue !== null && defaultValue !== undefined) { + set(data, path, defaultValue); + } }; -export const defaultValueProcess: ProcessorFn = async (context: DefaultValueContext) => { - return defaultValueProcessSync(context); +export const defaultValueProcess: ProcessorFn = async ( + context: DefaultValueContext, +) => { + return defaultValueProcessSync(context); }; -export const defaultValueProcessSync: ProcessorFnSync = (context: DefaultValueContext) => { - customDefaultValueProcessSync(context); - serverDefaultValueProcessSync(context); +export const defaultValueProcessSync: ProcessorFnSync = ( + context: DefaultValueContext, +) => { + customDefaultValueProcessSync(context); + serverDefaultValueProcessSync(context); }; export const customDefaultValueProcessInfo: ProcessorInfo = { - name: 'customDefaultValue', - process: customDefaultValueProcess, - processSync: customDefaultValueProcessSync, - shouldProcess: hasCustomDefaultValue, + name: 'customDefaultValue', + process: customDefaultValueProcess, + processSync: customDefaultValueProcessSync, + shouldProcess: hasCustomDefaultValue, }; export const serverDefaultValueProcessInfo: ProcessorInfo = { - name: 'serverDefaultValue', - process: serverDefaultValueProcess, - processSync: serverDefaultValueProcessSync, - shouldProcess: hasServerDefaultValue, + name: 'serverDefaultValue', + process: serverDefaultValueProcess, + processSync: serverDefaultValueProcessSync, + shouldProcess: hasServerDefaultValue, }; export const defaultValueProcessInfo: ProcessorInfo = { - name: 'defaultValue', - process: defaultValueProcess, - processSync: defaultValueProcessSync, - shouldProcess: hasDefaultValue, + name: 'defaultValue', + process: defaultValueProcess, + processSync: defaultValueProcessSync, + shouldProcess: hasDefaultValue, }; diff --git a/src/process/dereference/index.ts b/src/process/dereference/index.ts index b0850c90..042315b8 100644 --- a/src/process/dereference/index.ts +++ b/src/process/dereference/index.ts @@ -1,27 +1,29 @@ -import { ProcessorError } from "error"; +import { ProcessorError } from 'error'; import { - ProcessorFn, - ProcessorScope, - ProcessorContext, - ProcessorInfo, - Component, - DataTableComponent -} from "types"; -import { fastCloneDeep } from "utils"; + ProcessorFn, + ProcessorScope, + ProcessorContext, + ProcessorInfo, + Component, + DataTableComponent, +} from 'types'; +import { fastCloneDeep } from 'utils'; type DereferenceScope = ProcessorScope & { - dereference: { - [path: string]: Component[]; - } -} + dereference: { + [path: string]: Component[]; + }; +}; const isDereferenceableDataTableComponent = (component: any): component is DataTableComponent => { - return component - && component.type === 'datatable' - && component.fetch?.enableFetch === true - && component.fetch?.dataSrc === 'resource' - && typeof component.fetch?.resource === 'string'; -} + return ( + component && + component.type === 'datatable' && + component.fetch?.enableFetch === true && + component.fetch?.dataSrc === 'resource' && + typeof component.fetch?.resource === 'string' + ); +}; /** * This function is used to dereference reference IDs contained in the form. @@ -29,32 +31,35 @@ const isDereferenceableDataTableComponent = (component: any): component is DataT * @todo Add support for other components (if applicable) and for submission data dereferencing (e.g. save-as-reference, currently a property action). */ export const dereferenceProcess: ProcessorFn = async (context) => { - const { component, config, scope, path } = context; - if (!scope.dereference) { - scope.dereference = {}; - } - if (!isDereferenceableDataTableComponent(component)) { - return; - } - if (!config?.database) { - throw new ProcessorError('Cannot dereference resource value without a database config object', context, 'dereference'); - } + const { component, config, scope, path } = context; + if (!scope.dereference) { + scope.dereference = {}; + } + if (!isDereferenceableDataTableComponent(component)) { + return; + } + if (!config?.database) { + throw new ProcessorError( + 'Cannot dereference resource value without a database config object', + context, + 'dereference', + ); + } - try { - const components = await config.database?.dereferenceDataTableComponent(component); - const vmCompatibleComponents = fastCloneDeep(components); - scope.dereference[path] = vmCompatibleComponents; - // Modify the components in place; we have to do this now as opposed to a "post-processor" step because - // eachComponentDataAsync will immediately turn around and introspect these components in the case of Data Table - component.components = vmCompatibleComponents; - } - catch (err: any) { - throw new ProcessorError(err.message || err, context, 'dereference'); - } -} + try { + const components = await config.database?.dereferenceDataTableComponent(component); + const vmCompatibleComponents = fastCloneDeep(components); + scope.dereference[path] = vmCompatibleComponents; + // Modify the components in place; we have to do this now as opposed to a "post-processor" step because + // eachComponentDataAsync will immediately turn around and introspect these components in the case of Data Table + component.components = vmCompatibleComponents; + } catch (err: any) { + throw new ProcessorError(err.message || err, context, 'dereference'); + } +}; export const dereferenceProcessInfo: ProcessorInfo, void> = { - name: 'dereference', - shouldProcess: () => true, - process: dereferenceProcess, -} + name: 'dereference', + shouldProcess: () => true, + process: dereferenceProcess, +}; diff --git a/src/process/fetch/__tests__/fetch.test.ts b/src/process/fetch/__tests__/fetch.test.ts index fbb97fa2..1aef9201 100644 --- a/src/process/fetch/__tests__/fetch.test.ts +++ b/src/process/fetch/__tests__/fetch.test.ts @@ -1,20 +1,3 @@ -import { expect } from 'chai'; -import { process } from '../../process' -import { fetchProcessInfo } from '../index'; -import { FetchScope, ProcessContext } from 'types'; - -const processForm = async (form: any, submission: any) => { - const context: ProcessContext = { - processors: [fetchProcessInfo], - components: form.components, - data: submission.data, - scope: {} - }; - await process(context); - return context; -}; - -describe('Fetch processor', () => { - it('Perform a fetch operation.', async () => { - }); -}); \ No newline at end of file +describe('Fetch processor', function () { + it('Perform a fetch operation.', async function () {}); +}); diff --git a/src/process/fetch/index.ts b/src/process/fetch/index.ts index 5316d51a..b0537a75 100644 --- a/src/process/fetch/index.ts +++ b/src/process/fetch/index.ts @@ -1,102 +1,118 @@ -import { ProcessorFn, ProcessorInfo, FetchContext, FetchScope, FetchFn, DataSourceComponent, FilterContext } from 'types'; +import { + ProcessorFn, + ProcessorInfo, + FetchContext, + FetchScope, + FetchFn, + DataSourceComponent, + FilterContext, +} from 'types'; import { get, set } from 'lodash'; import { Evaluator } from 'utils'; import { getComponentKey } from 'utils/formUtil'; export const shouldFetch = (context: FetchContext): boolean => { - const { component, config } = context; - if ( - component.type !== 'datasource' || - (config?.server && !get(component, 'trigger.server', false)) - ) { - return false; - } - return true; + const { component, config } = context; + if ( + component.type !== 'datasource' || + (config?.server && !get(component, 'trigger.server', false)) + ) { + return false; + } + return true; }; export const fetchProcess: ProcessorFn = async (context: FetchContext) => { - const { component, row, evalContext, path, scope, config } = context; - let _fetch: FetchFn | null = null; - try { - _fetch = context.fetch ? context.fetch : fetch; - } - catch (err) { - _fetch = null; - } - if (!_fetch) { - console.log('You must provide a fetch interface to the fetch processor.'); - return; - } - if (!shouldFetch(context)) { - return; - } - if (!scope.fetched) scope.fetched = {}; - const evalContextValue = evalContext ? evalContext(context) : context; - const url = Evaluator.interpolateString(get(component, 'fetch.url', ''), evalContextValue); - if (!url) { - return; - } - const request: any = { - method: get(component, 'fetch.method', 'get').toUpperCase(), - headers: {} - }; + const { component, row, evalContext, path, scope, config } = context; + let _fetch: FetchFn | null = null; + try { + _fetch = context.fetch ? context.fetch : fetch; + } catch (ignoreErr) { + _fetch = null; + } + if (!_fetch) { + console.log('You must provide a fetch interface to the fetch processor.'); + return; + } + if (!shouldFetch(context)) { + return; + } + if (!scope.fetched) scope.fetched = {}; + const evalContextValue = evalContext ? evalContext(context) : context; + const url = Evaluator.interpolateString(get(component, 'fetch.url', ''), evalContextValue); + if (!url) { + return; + } + const request: any = { + method: get(component, 'fetch.method', 'get').toUpperCase(), + headers: {}, + }; - if ( - config?.headers && - (component as DataSourceComponent)?.fetch && - (component as DataSourceComponent)?.fetch?.forwardHeaders - ) { - request.headers = JSON.parse(JSON.stringify(config.headers)); - delete request.headers['host']; - delete request.headers['content-length']; - delete request.headers['content-type']; - delete request.headers['connection']; - delete request.headers['cache-control']; - } + if ( + config?.headers && + (component as DataSourceComponent)?.fetch && + (component as DataSourceComponent)?.fetch?.forwardHeaders + ) { + request.headers = JSON.parse(JSON.stringify(config.headers)); + delete request.headers['host']; + delete request.headers['content-length']; + delete request.headers['content-type']; + delete request.headers['connection']; + delete request.headers['cache-control']; + } - request.headers['Accept'] = '*/*'; - request.headers['user-agent'] = 'Form.io DataSource Component'; - get(component, 'fetch.headers', []).map((header: any) => { - header.value = Evaluator.interpolateString(header.value, evalContextValue); - if (header.value && header.key) { - request.headers[header.key] = header.value; - } - return header; - }); - - if (get(component, 'fetch.authenticate', false) && config?.tokens) { - Object.assign(request.headers, config.tokens); + request.headers['Accept'] = '*/*'; + request.headers['user-agent'] = 'Form.io DataSource Component'; + get(component, 'fetch.headers', []).map((header: any) => { + header.value = Evaluator.interpolateString(header.value, evalContextValue); + if (header.value && header.key) { + request.headers[header.key] = header.value; } + return header; + }); - const body = get(component, 'fetch.specifyBody', ''); - if (request.method === 'POST') { - request.body = JSON.stringify(Evaluator.evaluate(body, evalContextValue, 'body')); - } + if (get(component, 'fetch.authenticate', false) && config?.tokens) { + Object.assign(request.headers, config.tokens); + } - try { - // Perform the fetch. - const result = await (await _fetch(url, request)).json(); - const mapFunction = get(component, 'fetch.mapFunction'); + const body = get(component, 'fetch.specifyBody', ''); + if (request.method === 'POST') { + request.body = JSON.stringify(Evaluator.evaluate(body, evalContextValue, 'body')); + } - // Set the row data of the fetched value. - const key = getComponentKey(component); - set(row, key, mapFunction ? Evaluator.evaluate(mapFunction, { - ...evalContextValue, - ...{responseData: result} - }, 'value') : result); + try { + // Perform the fetch. + const result = await (await _fetch(url, request)).json(); + const mapFunction = get(component, 'fetch.mapFunction'); - // Make sure the value does not get filtered for now... - if (!(scope as FilterContext).filter) (scope as FilterContext).filter = {}; - (scope as FilterContext).filter[path] = true; - scope.fetched[path] = true; - } - catch (err: any) { - console.log(err.message); - } + // Set the row data of the fetched value. + const key = getComponentKey(component); + set( + row, + key, + mapFunction + ? Evaluator.evaluate( + mapFunction, + { + ...evalContextValue, + ...{ responseData: result }, + }, + 'value', + ) + : result, + ); + + // Make sure the value does not get filtered for now... + if (!(scope as FilterContext).filter) (scope as FilterContext).filter = {}; + (scope as FilterContext).filter[path] = true; + scope.fetched[path] = true; + } catch (err: any) { + console.log(err.message); + } }; export const fetchProcessInfo: ProcessorInfo = { - name: 'fetch', - process: fetchProcess, - shouldProcess: shouldFetch, -}; \ No newline at end of file + name: 'fetch', + process: fetchProcess, + shouldProcess: shouldFetch, +}; diff --git a/src/process/filter/__tests__/filter.test.ts b/src/process/filter/__tests__/filter.test.ts index 455ce9a2..031a355a 100644 --- a/src/process/filter/__tests__/filter.test.ts +++ b/src/process/filter/__tests__/filter.test.ts @@ -1,139 +1,109 @@ -import { expect } from "chai"; +import { expect } from 'chai'; -import { filterProcessSync } from "../"; -import { generateProcessorContext } from "../../__tests__/fixtures/util"; -import { FilterScope, ProcessorContext } from "types"; +import { filterProcessSync } from '../'; +import { generateProcessorContext } from '../../__tests__/fixtures/util'; +import { FilterScope, ProcessorContext } from 'types'; -it("Should not filter empty array value for dataGrid component", async () => { - const dataGridComp = { - type: "datagrid", - key: "dataGrid", - input: true, - path: "dataGrid", - components: [ - { - type: "textfield", - key: "textField", - input: true, - label: "Text Field", - }, - ], - }; - const data = { - dataGrid: [], - }; - const context: any = generateProcessorContext(dataGridComp, data); - filterProcessSync(context); - expect(context.scope.filter).to.deep.equal({ - dataGrid: { compModelType: "nestedArray", include: true, value: [] }, +describe('Filter processor', function () { + it('Should not filter empty array value for dataGrid component', async function () { + const dataGridComp = { + type: 'datagrid', + key: 'dataGrid', + input: true, + path: 'dataGrid', + components: [ + { + type: 'textfield', + key: 'textField', + input: true, + label: 'Text Field', + }, + ], + }; + const data = { + dataGrid: [], + }; + const context: any = generateProcessorContext(dataGridComp, data); + filterProcessSync(context); + expect(context.scope.filter).to.deep.equal({ + dataGrid: { compModelType: 'nestedArray', include: true, value: [] }, + }); }); -}); -it("Should not filter empty array value for editGrid component", async () => { - const editGridComp = { - type: "editgrid", - key: "editGrid", - input: true, - path: "editGrid", - components: [ - { - type: "textfield", - key: "textField", - input: true, - label: "Text Field", - }, - ], - }; - const data = { - editGrid: [], - }; - const context: any = generateProcessorContext(editGridComp, data); - filterProcessSync(context); - expect(context.scope.filter).to.deep.equal({ - editGrid: { compModelType: "nestedArray", include: true, value: [] }, + it('Should not filter empty array value for editGrid component', async function () { + const editGridComp = { + type: 'editgrid', + key: 'editGrid', + input: true, + path: 'editGrid', + components: [ + { + type: 'textfield', + key: 'textField', + input: true, + label: 'Text Field', + }, + ], + }; + const data = { + editGrid: [], + }; + const context: any = generateProcessorContext(editGridComp, data); + filterProcessSync(context); + expect(context.scope.filter).to.deep.equal({ + editGrid: { compModelType: 'nestedArray', include: true, value: [] }, + }); }); -}); -it("Should not filter empty array value for dataTable component", async () => { - const dataTableComp = { - type: "datatable", - key: "dataTable", - input: true, - path: "dataTable", - components: [ - { - type: "textfield", - key: "textField", - input: true, - label: "Text Field", - }, - ], - }; - const data = { - dataTable: [], - }; - const context: any = generateProcessorContext(dataTableComp, data); - filterProcessSync(context); - expect(context.scope.filter).to.deep.equal({ - dataTable: { compModelType: "nestedArray", include: true, value: [] }, + it('Should not filter empty array value for dataTable component', async function () { + const dataTableComp = { + type: 'datatable', + key: 'dataTable', + input: true, + path: 'dataTable', + components: [ + { + type: 'textfield', + key: 'textField', + input: true, + label: 'Text Field', + }, + ], + }; + const data = { + dataTable: [], + }; + const context: any = generateProcessorContext(dataTableComp, data); + filterProcessSync(context); + expect(context.scope.filter).to.deep.equal({ + dataTable: { compModelType: 'nestedArray', include: true, value: [] }, + }); }); -}); -it("Should not filter coordinates for Tagpad component", async () => { - const tagpadComp = { - label: 'Tagpad', - imageUrl: 'https://onetreeplanted.org/cdn/shop/articles/nature_facts_1600x.jpg?v=1705008496', - tableView: false, - validateWhenHidden: false, - key: 'tagpad', - path: 'tagpad', - type: 'tagpad', - input: true, - components: [ - { - label: 'Text Field', - applyMaskOn: 'change', - tableView: true, - validateWhenHidden: false, - key: 'textField', - type: 'textfield', - input: true, - }, - ], - }; - const data = { - tagpad: [ - { - coordinate: { - x: 83, - y: 61, - width: 280, - height: 133, - }, - data: { - textField: 'test1', - }, - }, - { - coordinate: { - x: 194, - y: 93, - width: 280, - height: 133, - }, - data: { - textField: 'test2', + it('Should not filter coordinates for Tagpad component', async function () { + const tagpadComp = { + label: 'Tagpad', + imageUrl: 'https://onetreeplanted.org/cdn/shop/articles/nature_facts_1600x.jpg?v=1705008496', + tableView: false, + validateWhenHidden: false, + key: 'tagpad', + path: 'tagpad', + type: 'tagpad', + input: true, + components: [ + { + label: 'Text Field', + applyMaskOn: 'change', + tableView: true, + validateWhenHidden: false, + key: 'textField', + type: 'textfield', + input: true, }, - }, - ], - }; - const context: any = generateProcessorContext(tagpadComp, data); - filterProcessSync(context); - expect(context.scope.filter).to.deep.equal({ - tagpad: { - compModelType: 'nestedDataArray', - include: true, - value: [ + ], + }; + const data = { + tagpad: [ { coordinate: { x: 83, @@ -141,7 +111,9 @@ it("Should not filter coordinates for Tagpad component", async () => { width: 280, height: 133, }, - data: {}, + data: { + textField: 'test1', + }, }, { coordinate: { @@ -150,45 +122,75 @@ it("Should not filter coordinates for Tagpad component", async () => { width: 280, height: 133, }, - data: {}, + data: { + textField: 'test2', + }, }, ], - }, + }; + const context: any = generateProcessorContext(tagpadComp, data); + filterProcessSync(context); + expect(context.scope.filter).to.deep.equal({ + tagpad: { + compModelType: 'nestedDataArray', + include: true, + value: [ + { + coordinate: { + x: 83, + y: 61, + width: 280, + height: 133, + }, + data: {}, + }, + { + coordinate: { + x: 194, + y: 93, + width: 280, + height: 133, + }, + data: {}, + }, + ], + }, + }); }); -}); -it("Should not filter the datamap component", async () => { - const dataMapComp = { - label: "Data Map", - tableView: false, - validateWhenHidden: false, - key: "dataMap", - type: "datamap", - path: "dataMap", - input: true, - valueComponent: { - type: "textfield", - key: "value", - label: "Value", + it('Should not filter the datamap component', async function () { + const dataMapComp = { + label: 'Data Map', + tableView: false, + validateWhenHidden: false, + key: 'dataMap', + type: 'datamap', + path: 'dataMap', input: true, - hideLabel: true, - tableView: true, - }, - }; + valueComponent: { + type: 'textfield', + key: 'value', + label: 'Value', + input: true, + hideLabel: true, + tableView: true, + }, + }; - const data = { - dataMap: { - foo: "bar", - baz: "biz" - }, - }; + const data = { + dataMap: { + foo: 'bar', + baz: 'biz', + }, + }; - const context: ProcessorContext = generateProcessorContext(dataMapComp, data); - filterProcessSync(context); - expect(context.scope.filter).to.deep.equal({ - dataMap: { - compModelType: "map", - include: true, - } + const context: ProcessorContext = generateProcessorContext(dataMapComp, data); + filterProcessSync(context); + expect(context.scope.filter).to.deep.equal({ + dataMap: { + compModelType: 'map', + include: true, + }, + }); }); }); diff --git a/src/process/filter/index.ts b/src/process/filter/index.ts index a645a9b0..72186af1 100644 --- a/src/process/filter/index.ts +++ b/src/process/filter/index.ts @@ -1,11 +1,11 @@ -import { FilterContext, FilterScope, ProcessorFn, ProcessorFnSync, ProcessorInfo } from "types"; +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 { Utils } from 'utils'; +import { get, isObject } from 'lodash'; +import { getComponentAbsolutePath } from 'utils/formUtil'; export const filterProcessSync: ProcessorFnSync = (context: FilterContext) => { const { scope, component } = context; - let { value } = context; + const { value } = context; const absolutePath = getComponentAbsolutePath(component); if (!scope.filter) scope.filter = {}; if (value !== undefined) { @@ -15,28 +15,28 @@ export const filterProcessSync: ProcessorFnSync = (context: FilterC scope.filter[absolutePath] = { compModelType: modelType, include: true, - value: { data: {} } + value: { data: {} }, }; break; case 'nestedArray': scope.filter[absolutePath] = { compModelType: modelType, include: true, - value: [] + value: [], }; break; case 'nestedDataArray': scope.filter[absolutePath] = { compModelType: modelType, include: true, - value: Array.isArray(value) ? value.map(v => ({...v, data: {}})) : [], + value: Array.isArray(value) ? value.map((v) => ({ ...v, data: {} })) : [], }; break; case 'object': scope.filter[absolutePath] = { compModelType: modelType, include: true, - value: (component.type === 'address') ? false : {} + value: component.type === 'address' ? false : {}, }; break; default: @@ -62,8 +62,7 @@ export const filterPostProcess: ProcessorFnSync = (context: FilterC if (scope.filter[path].value) { if (isObject(value) && scope.filter[path].value?.data) { value = { ...value, ...scope.filter[path].value }; - } - else { + } else { value = scope.filter[path].value; } } @@ -78,5 +77,5 @@ export const filterProcessInfo: ProcessorInfo = { process: filterProcess, processSync: filterProcessSync, postProcess: filterPostProcess, - shouldProcess: (context: FilterContext) => true, + shouldProcess: () => true, }; diff --git a/src/process/hideChildren.ts b/src/process/hideChildren.ts index d1ad4dbe..aa5e7114 100644 --- a/src/process/hideChildren.ts +++ b/src/process/hideChildren.ts @@ -1,39 +1,39 @@ import { - ProcessorScope, - ProcessorContext, - ProcessorInfo, - ProcessorFnSync, - ConditionsScope, - ProcessorFn, -} from "types"; -import { registerEphemeralState } from "utils"; + ProcessorScope, + ProcessorContext, + ProcessorInfo, + ProcessorFnSync, + ConditionsScope, + ProcessorFn, +} from 'types'; +import { registerEphemeralState } from 'utils'; /** * This processor function checks components for the `hidden` property and, if children are present, sets them to hidden as well. */ export const hideChildrenProcessor: ProcessorFnSync = (context) => { - const { component, path, parent, scope } = context; - // 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 path === cond.path && cond.conditionallyHidden; - }); + const { component, path, parent, scope } = context; + // 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 path === cond.path && cond.conditionallyHidden; + }); - if (!scope.conditionals) { - scope.conditionals = []; - } + if (!scope.conditionals) { + scope.conditionals = []; + } - if (isConditionallyHidden || component.hidden || parent?.ephemeralState?.conditionallyHidden) { - registerEphemeralState(component, 'conditionallyHidden', true); - } -} + if (isConditionallyHidden || component.hidden || parent?.ephemeralState?.conditionallyHidden) { + registerEphemeralState(component, 'conditionallyHidden', true); + } +}; export const hideChildrenProcessorAsync: ProcessorFn = async (context) => { - return hideChildrenProcessor(context); + return hideChildrenProcessor(context); }; export const hideChildrenProcessorInfo: ProcessorInfo, void> = { - name: 'hideChildren', - shouldProcess: () => true, - processSync: hideChildrenProcessor, - process: hideChildrenProcessorAsync, -} + name: 'hideChildren', + shouldProcess: () => true, + processSync: hideChildrenProcessor, + process: hideChildrenProcessorAsync, +}; diff --git a/src/process/logic/index.ts b/src/process/logic/index.ts index a298e742..f0ce733c 100644 --- a/src/process/logic/index.ts +++ b/src/process/logic/index.ts @@ -1,18 +1,18 @@ -import { LogicContext, LogicScope, ProcessorFn, ProcessorFnSync } from "types"; -import { applyActions, hasLogic } from "utils/logic"; +import { LogicContext, LogicScope, ProcessorFn, ProcessorFnSync } from 'types'; +import { applyActions, hasLogic } from 'utils/logic'; // This processor ensures that a "linked" row context is provided to every component. export const logicProcessSync: ProcessorFnSync = (context: LogicContext) => { - return applyActions(context); + return applyActions(context); }; export const logicProcess: ProcessorFn = async (context: LogicContext) => { - return logicProcessSync(context); + return logicProcessSync(context); }; export const logicProcessInfo = { - name: 'logic', - process: logicProcess, - processSync: logicProcessSync, - shouldProcess: hasLogic -}; \ No newline at end of file + name: 'logic', + process: logicProcess, + processSync: logicProcessSync, + shouldProcess: hasLogic, +}; diff --git a/src/process/normalize/__tests__/normalize.test.ts b/src/process/normalize/__tests__/normalize.test.ts index c819aad7..e56e0b2d 100644 --- a/src/process/normalize/__tests__/normalize.test.ts +++ b/src/process/normalize/__tests__/normalize.test.ts @@ -1,326 +1,341 @@ import { expect } from 'chai'; -import { TimeComponent, SelectBoxesComponent, ProcessorContext, ProcessorScope, DayComponent } from 'types'; +import { + TimeComponent, + SelectBoxesComponent, + ProcessorContext, + ProcessorScope, + DayComponent, +} from 'types'; import { normalizeProcessSync } from '../'; import { generateProcessorContext } from '../../__tests__/fixtures/util'; -it('Should normalize a time component with a valid time value that doees not match dataFormat', async () => { - const timeComp: TimeComponent = { - type: 'time', - key: 'time', - label: 'Time', - input: true, - dataFormat: 'HH:mm:ss', - }; - const data = { time: '12:00' }; - const context: ProcessorContext = generateProcessorContext(timeComp, data); - normalizeProcessSync(context); - expect(context.data).to.deep.equal({ time: '12:00:00' }); -}); +describe('Normalize processor', function () { + it('Should normalize a time component with a valid time value that doees not match dataFormat', async function () { + const timeComp: TimeComponent = { + type: 'time', + key: 'time', + label: 'Time', + input: true, + dataFormat: 'HH:mm:ss', + }; + const data = { time: '12:00' }; + const context: ProcessorContext = generateProcessorContext(timeComp, data); + normalizeProcessSync(context); + expect(context.data).to.deep.equal({ time: '12:00:00' }); + }); -it('Should normalize a select boxes component with an incorrect data model', () => { - const selectBoxesComp: SelectBoxesComponent = { - type: 'selectboxes', - key: 'selectBoxes', - label: 'Select Boxes', - input: true, - values: [ - { label: 'One', value: 'one' }, - { label: 'Two', value: 'two' }, - { label: 'Three', value: 'three' }, - ], - }; - const data = { - selectBoxes: '', - }; - const context: ProcessorContext = generateProcessorContext(selectBoxesComp, data); - normalizeProcessSync(context); - expect(context.data).to.deep.equal({ selectBoxes: {} }); -}); + it('Should normalize a select boxes component with an incorrect data model', function () { + const selectBoxesComp: SelectBoxesComponent = { + type: 'selectboxes', + key: 'selectBoxes', + label: 'Select Boxes', + input: true, + values: [ + { label: 'One', value: 'one' }, + { label: 'Two', value: 'two' }, + { label: 'Three', value: 'three' }, + ], + }; + const data = { + selectBoxes: '', + }; + const context: ProcessorContext = generateProcessorContext( + selectBoxesComp, + data, + ); + normalizeProcessSync(context); + expect(context.data).to.deep.equal({ selectBoxes: {} }); + }); -it('Should normalize an email component value', () => { - const emailComp = { - type: 'email', - key: 'email', - input: true, - label: 'Email', - }; - const data = { - email: 'BrendanBond@Gmail.com', - }; - const context: ProcessorContext = generateProcessorContext(emailComp, data); - normalizeProcessSync(context); - expect(context.data).to.deep.equal({ email: 'brendanbond@gmail.com' }); -}); + it('Should normalize an email component value', function () { + const emailComp = { + type: 'email', + key: 'email', + input: true, + label: 'Email', + }; + const data = { + email: 'BrendanBond@Gmail.com', + }; + const context: ProcessorContext = generateProcessorContext(emailComp, data); + normalizeProcessSync(context); + expect(context.data).to.deep.equal({ email: 'brendanbond@gmail.com' }); + }); -it('Should normalize a radio component with a string value', () => { - const radioComp = { - type: 'radio', - key: 'radio', - input: true, - label: 'Radio', - values: [ - { - label: 'Yes', - value: 'true', - }, - { - label: 'No', - value: 'false', - }, - ], - }; - const data = { - radio: 'true', - }; - const context: ProcessorContext = generateProcessorContext(radioComp, data); - normalizeProcessSync(context); - expect(context.data).to.deep.equal({ radio: true }); -}); -it('Should normalize a radio component with a string value of false', () => { - const radioComp = { - type: 'radio', - key: 'radio', - input: true, - label: 'Radio', - values: [ - { - label: 'Yes', - value: 'true', - }, - { - label: 'No', - value: 'false', - }, - ], - }; - const data = { - radio: 'false', - }; - const context: ProcessorContext = generateProcessorContext(radioComp, data); - normalizeProcessSync(context); - expect(context.data).to.deep.equal({ radio: false }); -}); + it('Should normalize a radio component with a string value', function () { + const radioComp = { + type: 'radio', + key: 'radio', + input: true, + label: 'Radio', + values: [ + { + label: 'Yes', + value: 'true', + }, + { + label: 'No', + value: 'false', + }, + ], + }; + const data = { + radio: 'true', + }; + const context: ProcessorContext = generateProcessorContext(radioComp, data); + normalizeProcessSync(context); + expect(context.data).to.deep.equal({ radio: true }); + }); -it('Should normalize a radio component value with a number', () => { - const radioComp = { - type: 'radio', - key: 'radio', - input: true, - label: 'Radio', - values: [ - { - label: 'Yes', - value: '1', - }, - { - label: 'No', - value: '0', - }, - ], - }; - const data = { - radio: '0', - }; - const context: ProcessorContext = generateProcessorContext(radioComp, data); - normalizeProcessSync(context); - expect(context.data).to.deep.equal({ radio: 0 }); -}); + it('Should normalize a radio component with a string value of false', function () { + const radioComp = { + type: 'radio', + key: 'radio', + input: true, + label: 'Radio', + values: [ + { + label: 'Yes', + value: 'true', + }, + { + label: 'No', + value: 'false', + }, + ], + }; + const data = { + radio: 'false', + }; + const context: ProcessorContext = generateProcessorContext(radioComp, data); + normalizeProcessSync(context); + expect(context.data).to.deep.equal({ radio: false }); + }); -it('Should normalize a radio component value with a string if storage type is set to string', () => { - const radioComp = { - type: 'radio', - key: 'radio', - input: true, - label: 'Radio', - dataType: 'string', - values: [ - { - label: '1', - value: 1, - }, - { - label: '0', - value: 0, - }, - ], - }; - const data = { - radio: 0, - }; - const context: ProcessorContext = generateProcessorContext(radioComp, data); - normalizeProcessSync(context); - expect(context.data).to.deep.equal({ radio: '0' }); -}); -it('Should normalize a radio component value with a number if storage type is set to number', () => { - const radioComp = { - type: 'radio', - key: 'radio', - input: true, - label: 'Radio', - dataType: 'number', - values: [ - { - label: '1', - value: 1, - }, - { - label: '0', - value: 2, - }, - ], - }; - const data = { - radio: 1, - }; - const context: ProcessorContext = generateProcessorContext(radioComp, data); - normalizeProcessSync(context); - expect(context.data).to.deep.equal({ radio: 1 }); -}); -it('Should normalize a radio component value with a boolean if storage type is set to boolean', () => { - const radioComp = { - type: 'radio', - key: 'radio', - input: true, - label: 'Radio', - dataType: 'boolean', - values: [ - { - label: '1', - value: 'true', - }, - { - label: '0', - value: 'false', - }, - ], - }; - const data = { - radio: true, - }; - const context: ProcessorContext = generateProcessorContext(radioComp, data); - normalizeProcessSync(context); - expect(context.data).to.deep.equal({ radio: true }); -}); -it('Should normalize a radio component value with a false boolean if storage type is set to boolean and has value of "false"', () => { - const radioComp = { - type: 'radio', - key: 'radio', - input: true, - label: 'Radio', - dataType: 'boolean', - values: [ - { - label: '1', - value: 'true', - }, - { - label: '0', - value: 'false', - }, - ], - }; - const data = { - radio: 'false', - }; - const context: ProcessorContext = generateProcessorContext(radioComp, data); - normalizeProcessSync(context); - expect(context.data).to.deep.equal({ radio: false }); -}); + it('Should normalize a radio component value with a number', function () { + const radioComp = { + type: 'radio', + key: 'radio', + input: true, + label: 'Radio', + values: [ + { + label: 'Yes', + value: '1', + }, + { + label: 'No', + value: '0', + }, + ], + }; + const data = { + radio: '0', + }; + const context: ProcessorContext = generateProcessorContext(radioComp, data); + normalizeProcessSync(context); + expect(context.data).to.deep.equal({ radio: 0 }); + }); -it('Should normalize a radio component value with an object if storage type is set to string and value is an object', () => { - const radioComp = { - type: 'radio', - key: 'radio', - input: true, - label: 'Radio', - dataType: 'string', - values: [ - { - label: '1', - value: 'true', - }, - { - label: '0', - value: 'false', - }, - ], - }; - const data = { - radio: { test: 'test' }, - }; - const context: ProcessorContext = generateProcessorContext(radioComp, data); - normalizeProcessSync(context); - expect(context.data).to.deep.equal({ - radio: JSON.stringify({ test: 'test' }), + it('Should normalize a radio component value with a string if storage type is set to string', function () { + const radioComp = { + type: 'radio', + key: 'radio', + input: true, + label: 'Radio', + dataType: 'string', + values: [ + { + label: '1', + value: 1, + }, + { + label: '0', + value: 0, + }, + ], + }; + const data = { + radio: 0, + }; + const context: ProcessorContext = generateProcessorContext(radioComp, data); + normalizeProcessSync(context); + expect(context.data).to.deep.equal({ radio: '0' }); }); -}); -it('Should normalize a number component value with a string value', () => { - const numberComp = { - type: 'number', - key: 'number', - input: true, - label: 'Number', - }; - const data = { - number: '000123', - }; - const context: ProcessorContext = generateProcessorContext(numberComp, data); - normalizeProcessSync(context); - expect(context.data).to.deep.equal({ number: 123 }); -}); + it('Should normalize a radio component value with a number if storage type is set to number', function () { + const radioComp = { + type: 'radio', + key: 'radio', + input: true, + label: 'Radio', + dataType: 'number', + values: [ + { + label: '1', + value: 1, + }, + { + label: '0', + value: 2, + }, + ], + }; + const data = { + radio: 1, + }; + const context: ProcessorContext = generateProcessorContext(radioComp, data); + normalizeProcessSync(context); + expect(context.data).to.deep.equal({ radio: 1 }); + }); -it('Should normalize a number component value with a multiple values allowed', () => { - const numberComp = { - type: 'number', - key: 'number', - input: true, - label: 'Number', - multiple: true, - }; - const data = { - number: ['000.0123', '123'], - }; - const context: ProcessorContext = generateProcessorContext(numberComp, data); - normalizeProcessSync(context); - expect(context.data).to.deep.equal({ number: [0.0123, 123] }); -}); + it('Should normalize a radio component value with a boolean if storage type is set to boolean', function () { + const radioComp = { + type: 'radio', + key: 'radio', + input: true, + label: 'Radio', + dataType: 'boolean', + values: [ + { + label: '1', + value: 'true', + }, + { + label: '0', + value: 'false', + }, + ], + }; + const data = { + radio: true, + }; + const context: ProcessorContext = generateProcessorContext(radioComp, data); + normalizeProcessSync(context); + expect(context.data).to.deep.equal({ radio: true }); + }); -it('Should normalize a day component with disabled components ', async () => { - const dayComp: DayComponent = { - type: 'day', - key: 'day', - label: 'Day', - input: true, - defaultValue:'', - fields: { - day: {hide: true}, - month: {hide: false}, - year: {hide: false} - } - }; - const data = { day: '01/2025', }; - const context: ProcessorContext = generateProcessorContext(dayComp, data); - normalizeProcessSync(context); - expect(context.data).to.deep.equal({ day: '01/2025' }); -}); + it('Should normalize a radio component value with a false boolean if storage type is set to boolean and has value of "false"', function () { + const radioComp = { + type: 'radio', + key: 'radio', + input: true, + label: 'Radio', + dataType: 'boolean', + values: [ + { + label: '1', + value: 'true', + }, + { + label: '0', + value: 'false', + }, + ], + }; + const data = { + radio: 'false', + }; + const context: ProcessorContext = generateProcessorContext(radioComp, data); + normalizeProcessSync(context); + expect(context.data).to.deep.equal({ radio: false }); + }); -it('Should normalize a day component with disabled components and defaultValue', async () => { - const dayComp: DayComponent = { - type: 'day', - key: 'day', - label: 'Day', - input: true, - defaultValue: '01/2025', - fields: { - day: {hide: true}, - month: {hide: false}, - year: {hide: false} - } - }; - const data = { day: '01/2025', }; - const context: ProcessorContext = generateProcessorContext(dayComp, data); - normalizeProcessSync(context); - expect({ day: '01/2025' }).to.deep.equal({ day: '01/2025' }); -}); \ No newline at end of file + it('Should normalize a radio component value with an object if storage type is set to string and value is an object', function () { + const radioComp = { + type: 'radio', + key: 'radio', + input: true, + label: 'Radio', + dataType: 'string', + values: [ + { + label: '1', + value: 'true', + }, + { + label: '0', + value: 'false', + }, + ], + }; + const data = { + radio: { test: 'test' }, + }; + const context: ProcessorContext = generateProcessorContext(radioComp, data); + normalizeProcessSync(context); + expect(context.data).to.deep.equal({ + radio: JSON.stringify({ test: 'test' }), + }); + }); + + it('Should normalize a number component value with a string value', function () { + const numberComp = { + type: 'number', + key: 'number', + input: true, + label: 'Number', + }; + const data = { + number: '000123', + }; + const context: ProcessorContext = generateProcessorContext(numberComp, data); + normalizeProcessSync(context); + expect(context.data).to.deep.equal({ number: 123 }); + }); + + it('Should normalize a number component value with a multiple values allowed', function () { + const numberComp = { + type: 'number', + key: 'number', + input: true, + label: 'Number', + multiple: true, + }; + const data = { + number: ['000.0123', '123'], + }; + const context: ProcessorContext = generateProcessorContext(numberComp, data); + normalizeProcessSync(context); + expect(context.data).to.deep.equal({ number: [0.0123, 123] }); + }); + + it('Should normalize a day component with disabled components ', async function () { + const dayComp: DayComponent = { + type: 'day', + key: 'day', + label: 'Day', + input: true, + defaultValue: '', + fields: { + day: { hide: true }, + month: { hide: false }, + year: { hide: false }, + }, + }; + const data = { day: '01/2025' }; + const context: ProcessorContext = generateProcessorContext(dayComp, data); + normalizeProcessSync(context); + expect(context.data).to.deep.equal({ day: '01/2025' }); + }); + + it('Should normalize a day component with disabled components and defaultValue', async function () { + const dayComp: DayComponent = { + type: 'day', + key: 'day', + label: 'Day', + input: true, + defaultValue: '01/2025', + fields: { + day: { hide: true }, + month: { hide: false }, + year: { hide: false }, + }, + }; + const data = { day: '01/2025' }; + const context: ProcessorContext = generateProcessorContext(dayComp, data); + normalizeProcessSync(context); + expect({ day: '01/2025' }).to.deep.equal({ day: '01/2025' }); + }); +}); diff --git a/src/process/normalize/index.ts b/src/process/normalize/index.ts index 01092c2d..332deb6a 100644 --- a/src/process/normalize/index.ts +++ b/src/process/normalize/index.ts @@ -2,403 +2,420 @@ import { get, set, isString, toString, isNil, isObject, isNull } from 'lodash'; import dayjs from 'dayjs'; import customParseFormat from 'dayjs/plugin/customParseFormat'; import { - AddressComponent, - DayComponent, - EmailComponent, - ProcessorFnSync, - ProcessorFn, - RadioComponent, - RecaptchaComponent, - SelectComponent, - SelectBoxesComponent, - TagsComponent, - TextFieldComponent, - DefaultValueScope, - ProcessorInfo, - ProcessorContext, - TimeComponent, - NumberComponent -} from "types"; + AddressComponent, + DayComponent, + EmailComponent, + ProcessorFnSync, + ProcessorFn, + RadioComponent, + SelectComponent, + SelectBoxesComponent, + TagsComponent, + TextFieldComponent, + DefaultValueScope, + ProcessorInfo, + ProcessorContext, + TimeComponent, + NumberComponent, +} from 'types'; type NormalizeScope = DefaultValueScope & { - normalize?: { - [path: string]: any; - } -} - -dayjs.extend(customParseFormat) - -const isAddressComponent = (component: any): component is AddressComponent => component.type === "address"; -const isDayComponent = (component: any): component is DayComponent => component.type === "day"; -const isEmailComponent = (component:any): component is EmailComponent => component.type === "email"; -const isRadioComponent = (component: any): component is RadioComponent => component.type === "radio"; -const isRecaptchaComponent = (component: any): component is RecaptchaComponent => component.type === "recaptcha"; -const isSelectComponent = (component: any): component is SelectComponent => component.type === "select"; -const isSelectBoxesComponent = (component: any): component is SelectBoxesComponent => component.type === "selectboxes"; -const isTagsComponent = (component: any): component is TagsComponent => component.type === "tags"; -const isTextFieldComponent = (component: any): component is TextFieldComponent => component.type === "textfield"; -const isTimeComponent = (component: any): component is TimeComponent => component.type === "time"; -const isNumberComponent = (component: any): component is NumberComponent => component.type === "number"; + normalize?: { + [path: string]: any; + }; +}; + +dayjs.extend(customParseFormat); + +const isAddressComponent = (component: any): component is AddressComponent => + component.type === 'address'; +const isDayComponent = (component: any): component is DayComponent => component.type === 'day'; +const isEmailComponent = (component: any): component is EmailComponent => + component.type === 'email'; +const isRadioComponent = (component: any): component is RadioComponent => + component.type === 'radio'; +const isSelectComponent = (component: any): component is SelectComponent => + component.type === 'select'; +const isSelectBoxesComponent = (component: any): component is SelectBoxesComponent => + component.type === 'selectboxes'; +const isTagsComponent = (component: any): component is TagsComponent => component.type === 'tags'; +const isTextFieldComponent = (component: any): component is TextFieldComponent => + component.type === 'textfield'; +const isTimeComponent = (component: any): component is TimeComponent => component.type === 'time'; +const isNumberComponent = (component: any): component is NumberComponent => + component.type === 'number'; const normalizeAddressComponentValue = (component: AddressComponent, value: any) => { - if (!component.multiple && Boolean(component.enableManualMode) && value && !value.mode) { - return { - mode: 'autocomplete', - address: value, - } - } - return value; -} + if (!component.multiple && Boolean(component.enableManualMode) && value && !value.mode) { + return { + mode: 'autocomplete', + address: value, + }; + } + return value; +}; const getLocaleDateFormatInfo = (locale: string = 'en') => { - const formatInfo: {dayFirst?: boolean} = {}; + const formatInfo: { dayFirst?: boolean } = {}; - const day = 21; - const exampleDate = new Date(2017, 11, day); - const localDateString = exampleDate.toLocaleDateString(locale); + const day = 21; + const exampleDate = new Date(2017, 11, day); + const localDateString = exampleDate.toLocaleDateString(locale); - formatInfo.dayFirst = localDateString.slice(0, 2) === day.toString(); + formatInfo.dayFirst = localDateString.slice(0, 2) === day.toString(); - return formatInfo; + return formatInfo; }; const getLocaleDayFirst = (component: DayComponent, form: any) => { - if (component.useLocaleSettings) { - return getLocaleDateFormatInfo(form.options?.language).dayFirst; - } - return component.dayFirst; + if (component.useLocaleSettings) { + return getLocaleDateFormatInfo(form.options?.language).dayFirst; + } + return component.dayFirst; }; const normalizeDayComponentValue = (component: DayComponent, form: any, value: any) => { - // TODO: this is a quick and dirty port of the Day component's normalizeValue method, may need some updates - const valueMask = /^\d{2}\/\d{2}\/\d{4}$/; + // TODO: this is a quick and dirty port of the Day component's normalizeValue method, may need some updates + const valueMask = /^\d{2}\/\d{2}\/\d{4}$/; - const isDayFirst = getLocaleDayFirst(component, form); - const showDay = !get(component, 'fields.day.hide', false); - const showMonth = !get(component, 'fields.month.hide', false); - const showYear = !get(component, 'fields.year.hide', false); + const isDayFirst = getLocaleDayFirst(component, form); + const showDay = !get(component, 'fields.day.hide', false); + const showMonth = !get(component, 'fields.month.hide', false); + const showYear = !get(component, 'fields.year.hide', false); - if (!value || valueMask.test(value)) { - return value; + if (!value || valueMask.test(value)) { + return value; + } + const dateParts: string[] = []; + const valueParts = value.split('/'); + const [DAY, MONTH, YEAR] = component.dayFirst ? [0, 1, 2] : [1, 0, 2]; + const defaultValue = component.defaultValue ? component.defaultValue.split('/') : ''; + + let defaultDay = ''; + let defaultMonth = ''; + let defaultYear = ''; + + const getDayWithHiddenFields = (parts: Array) => { + let DAY, MONTH, YEAR; + [DAY, MONTH, YEAR] = component.dayFirst ? [0, 1, 2] : [1, 0, 2]; + if (!showDay) { + MONTH = MONTH === 0 ? 0 : MONTH - 1; + YEAR = YEAR - 1; + DAY = null; + } + if (!showMonth) { + if (!isNull(DAY)) { + DAY = DAY === 0 ? 0 : DAY - 1; + } + YEAR = YEAR - 1; + MONTH = null; } - let dateParts: string[] = []; - const valueParts = value.split('/'); - const [DAY, MONTH, YEAR] = component.dayFirst ? [0, 1, 2] : [1, 0, 2]; - const defaultValue = component.defaultValue ? component.defaultValue.split('/') : ''; - - let defaultDay = ''; - let defaultMonth = ''; - let defaultYear = ''; - - const getDayWithHiddenFields = (parts: Array) => { - let DAY, MONTH, YEAR - [DAY, MONTH, YEAR] = component.dayFirst ? [0, 1, 2] : [1, 0, 2]; - if (!showDay) { - MONTH = MONTH === 0 ? 0 : MONTH - 1; - YEAR = YEAR - 1; - DAY = null; - } - if (!showMonth) { - if (!isNull(DAY)) { - DAY = DAY === 0 ? 0 : DAY - 1; - } - YEAR = YEAR - 1; - MONTH = null; - } - if (!showYear) { - YEAR = null; - } - - return { - month: isNull(MONTH) ? '' : parts[MONTH], - day: isNull(DAY) ? '' : parts[DAY], - year: isNull(YEAR) ? '' : parts[YEAR], - } + if (!showYear) { + YEAR = null; } - const getNextPart = (shouldTake: boolean, defaultValue: string) => { - // Only push the part if it's not an empty string - const part: string = shouldTake ? valueParts.shift() : defaultValue; - if (part !== '') { - dateParts.push(part); - } - } + return { + month: isNull(MONTH) ? '' : parts[MONTH], + day: isNull(DAY) ? '' : parts[DAY], + year: isNull(YEAR) ? '' : parts[YEAR], + }; + }; - if(defaultValue) { - const hasHiddenFields = defaultValue.length !==3; - defaultDay = hasHiddenFields ? getDayWithHiddenFields(defaultValue).day : defaultValue[DAY]; - defaultMonth = hasHiddenFields ? getDayWithHiddenFields(defaultValue).month : defaultValue[MONTH]; - defaultYear = hasHiddenFields ? getDayWithHiddenFields(defaultValue).year : defaultValue[YEAR]; + const getNextPart = (shouldTake: boolean, defaultValue: string) => { + // Only push the part if it's not an empty string + const part: string = shouldTake ? valueParts.shift() : defaultValue; + if (part !== '') { + dateParts.push(part); } + }; - if (isDayFirst) { - getNextPart(showDay, defaultDay); - } + if (defaultValue) { + const hasHiddenFields = defaultValue.length !== 3; + defaultDay = hasHiddenFields ? getDayWithHiddenFields(defaultValue).day : defaultValue[DAY]; + defaultMonth = hasHiddenFields + ? getDayWithHiddenFields(defaultValue).month + : defaultValue[MONTH]; + defaultYear = hasHiddenFields ? getDayWithHiddenFields(defaultValue).year : defaultValue[YEAR]; + } - getNextPart(showMonth, defaultMonth); + if (isDayFirst) { + getNextPart(showDay, defaultDay); + } - if (!isDayFirst) { - getNextPart(showDay, defaultDay); - } + getNextPart(showMonth, defaultMonth); + + if (!isDayFirst) { + getNextPart(showDay, defaultDay); + } - getNextPart(showYear, defaultYear); + getNextPart(showYear, defaultYear); - return dateParts.join('/'); + return dateParts.join('/'); }; const normalizeRadioComponentValue = (value: any, dataType?: string) => { - switch(dataType) { - case 'number': - return +value; - case 'string': - return typeof value === 'object' ? JSON.stringify(value) : String(value); - case 'boolean': - return !(!value || value.toString() === 'false'); - } - const isEquivalent = toString(value) === Number(value).toString(); - if (!isNaN(parseFloat(value)) && isFinite(value) && isEquivalent) { - return +value; - } - - if (value === 'true') { - return true; - } - if (value === 'false') { - return false; - } - - return value; + switch (dataType) { + case 'number': + return +value; + case 'string': + return typeof value === 'object' ? JSON.stringify(value) : String(value); + case 'boolean': + return !(!value || value.toString() === 'false'); + } + const isEquivalent = toString(value) === Number(value).toString(); + if (!isNaN(parseFloat(value)) && isFinite(value) && isEquivalent) { + return +value; + } + + if (value === 'true') { + return true; + } + if (value === 'false') { + return false; + } + + return value; }; const normalizeSingleSelectComponentValue = (component: SelectComponent, value: any) => { - if (isNil(value)) { - return; - } - const valueIsObject = isObject(value); - //check if value equals to default emptyValue - if (valueIsObject && Object.keys(value).length === 0) { - return value; - } + if (isNil(value)) { + return; + } + const valueIsObject = isObject(value); + //check if value equals to default emptyValue + if (valueIsObject && Object.keys(value).length === 0) { + return value; + } + + const dataType = component.dataType || 'auto'; + const normalize = { + value, + number() { + const numberValue = Number(this.value); + const isEquivalent = value.toString() === numberValue.toString(); + + if ( + !Number.isNaN(numberValue) && + Number.isFinite(numberValue) && + value !== '' && + isEquivalent + ) { + this.value = numberValue; + } - const dataType = component.dataType || 'auto'; - const normalize = { - value, - number() { - const numberValue = Number(this.value); - const isEquivalent = value.toString() === numberValue.toString(); - - if (!Number.isNaN(numberValue) && Number.isFinite(numberValue) && value !== '' && isEquivalent) { - this.value = numberValue; - } - - return this; - }, - - boolean() { - if (isString(this.value) && (this.value.toLowerCase() === 'true' || this.value.toLowerCase() === 'false')) { - this.value = (this.value.toLowerCase() === 'true'); - } - return this; - }, - - string() { - this.value = String(this.value); - return this; - }, - - object() { - return this; - }, - - auto() { - if (isObject(this.value)) { - this.value = this.object().value; - } - else { - this.value = this.string().number().boolean().value; - } - return this; - } - }; + return this; + }, - try { - return normalize[dataType]().value; - } - catch (err) { - console.warn('Failed to normalize value', err); - return value; - } -} + boolean() { + if ( + isString(this.value) && + (this.value.toLowerCase() === 'true' || this.value.toLowerCase() === 'false') + ) { + this.value = this.value.toLowerCase() === 'true'; + } + return this; + }, + + string() { + this.value = String(this.value); + return this; + }, + + object() { + return this; + }, + + auto() { + if (isObject(this.value)) { + this.value = this.object().value; + } else { + this.value = this.string().number().boolean().value; + } + return this; + }, + }; + + try { + return normalize[dataType]().value; + } catch (err) { + console.warn('Failed to normalize value', err); + return value; + } +}; const normalizeSelectComponentValue = (component: SelectComponent, value: any) => { - if (component.multiple && Array.isArray(value)) { - return value.map((singleValue) => normalizeSingleSelectComponentValue(component, singleValue)); - } + if (component.multiple && Array.isArray(value)) { + return value.map((singleValue) => normalizeSingleSelectComponentValue(component, singleValue)); + } - return normalizeSingleSelectComponentValue(component, value); + return normalizeSingleSelectComponentValue(component, value); }; const normalizeSelectBoxesComponentValue = (value: any) => { - if (!value) { - value = {}; + if (!value) { + value = {}; + } + if (typeof value !== 'object') { + if (typeof value === 'string') { + return { + [value]: true, + }; + } else { + return {}; } - if (typeof value !== 'object') { - if (typeof value === 'string') { - return { - [value]: true - }; - } - else { - return {}; - } - } - if (Array.isArray(value)) { - return value.reduce((acc, curr) => { - return { ...acc, [curr]: true }; - }, {}); - } - - return value; + } + if (Array.isArray(value)) { + return value.reduce((acc, curr) => { + return { ...acc, [curr]: true }; + }, {}); + } + + return value; }; const normalizeTagsComponentValue = (component: TagsComponent, value: any) => { - const delimiter = component.delimeter || ','; - if ((!component.hasOwnProperty('storeas') || component.storeas === 'string') && Array.isArray(value)) { - return value.join(delimiter); - } - else if (component.storeas === 'array' && typeof value === 'string') { - return value.split(delimiter).filter(result => result); - } - return value; + const delimiter = component.delimeter || ','; + if ( + (!component.hasOwnProperty('storeas') || component.storeas === 'string') && + Array.isArray(value) + ) { + return value.join(delimiter); + } else if (component.storeas === 'array' && typeof value === 'string') { + return value.split(delimiter).filter((result) => result); + } + return value; }; const normalizeMaskValue = ( - component: TextFieldComponent, - defaultValues: DefaultValueScope['defaultValues'], - value: any, - path: string + component: TextFieldComponent, + defaultValues: DefaultValueScope['defaultValues'], + value: any, + path: string, ) => { - if (component.inputMasks && component.inputMasks.length > 0) { - if (!value || typeof value !== 'object') { - return { - value: value, - maskName: component.inputMasks[0].label - } - } - if (!value.value) { - const defaultValue = defaultValues?.find((defaultValue) => defaultValue.path === path); - value.value = Array.isArray(defaultValue) && defaultValue.length > 0 ? defaultValue[0] : defaultValue; - } + if (component.inputMasks && component.inputMasks.length > 0) { + if (!value || typeof value !== 'object') { + return { + value: value, + maskName: component.inputMasks[0].label, + }; } - return value; -} + if (!value.value) { + const defaultValue = defaultValues?.find((defaultValue) => defaultValue.path === path); + value.value = + Array.isArray(defaultValue) && defaultValue.length > 0 ? defaultValue[0] : defaultValue; + } + } + return value; +}; const normalizeTextFieldComponentValue = ( - component: TextFieldComponent, - defaultValues: DefaultValueScope['defaultValues'], - value: any, - path: string + component: TextFieldComponent, + defaultValues: DefaultValueScope['defaultValues'], + value: any, + path: string, ) => { - // If the component has truncate multiple spaces enabled, then normalize the value to remove extra spaces. - if (component.truncateMultipleSpaces && typeof value === 'string') { - value = value.trim().replace(/\s{2,}/g, ' '); - } - if (component.allowMultipleMasks && component.inputMasks && component.inputMasks.length > 0) { - if (Array.isArray(value)) { - return value.map((val) => normalizeMaskValue(component, defaultValues, val, path)); - } else { - return normalizeMaskValue(component, defaultValues, value, path); - } + // If the component has truncate multiple spaces enabled, then normalize the value to remove extra spaces. + if (component.truncateMultipleSpaces && typeof value === 'string') { + value = value.trim().replace(/\s{2,}/g, ' '); + } + if (component.allowMultipleMasks && component.inputMasks && component.inputMasks.length > 0) { + if (Array.isArray(value)) { + return value.map((val) => normalizeMaskValue(component, defaultValues, val, path)); + } else { + return normalizeMaskValue(component, defaultValues, value, path); } - return value; -} + } + return value; +}; // Allow submissions of time components in their visual "format" property by coercing them to the "dataFormat" property // i.e. "HH:mm" -> "HH:mm:ss" const normalizeTimeComponentValue = (component: TimeComponent, value: string) => { - const defaultDataFormat = 'HH:mm:ss'; - const defaultFormat = 'HH:mm'; - if (dayjs(value, component.format || defaultFormat, true).isValid()) { - return dayjs(value, component.format || defaultFormat, true).format(component.dataFormat || defaultDataFormat); - } - return value; + const defaultDataFormat = 'HH:mm:ss'; + const defaultFormat = 'HH:mm'; + if (dayjs(value, component.format || defaultFormat, true).isValid()) { + return dayjs(value, component.format || defaultFormat, true).format( + component.dataFormat || defaultDataFormat, + ); + } + return value; }; const normalizeSingleNumberComponentValue = (component: NumberComponent, value: any) => { - if (!isNaN(parseFloat(value)) && isFinite(value)) { - return +value; - } + if (!isNaN(parseFloat(value)) && isFinite(value)) { + return +value; + } - return value; -} + return value; +}; const normalizeNumberComponentValue = (component: NumberComponent, value: any) => { - if (component.multiple && Array.isArray(value)) { - return value.map((singleValue) => normalizeSingleNumberComponentValue(component, singleValue)); - } + if (component.multiple && Array.isArray(value)) { + return value.map((singleValue) => normalizeSingleNumberComponentValue(component, singleValue)); + } - return normalizeSingleNumberComponentValue(component, value); + return normalizeSingleNumberComponentValue(component, value); }; export const normalizeProcess: ProcessorFn = async (context) => { - return normalizeProcessSync(context); -} + return normalizeProcessSync(context); +}; export const normalizeProcessSync: ProcessorFnSync = (context) => { - const { component, form, scope, path, data, value } = context; - if (!scope.normalize) { - scope.normalize = {}; - } - let { defaultValues } = scope; - scope.normalize[path] = { - type: component.type, - normalized: false - }; - // First check for component-type-specific transformations - if (isAddressComponent(component)) { - set(data, path, normalizeAddressComponentValue(component, value)); - scope.normalize[path].normalized = true; - } else if (isDayComponent(component)) { - set(data, path, normalizeDayComponentValue(component, form, value)); - scope.normalize[path].normalized = true; - } else if (isEmailComponent(component)) { - if (value && typeof value === 'string') { - set(data, path, value.toLowerCase()); - scope.normalize[path].normalized = true; - } - } else if (isRadioComponent(component)) { - set(data, path, normalizeRadioComponentValue(value, component.dataType)); - scope.normalize[path].normalized = true; - } else if (isSelectComponent(component)) { - set(data, path, normalizeSelectComponentValue(component, value)); - scope.normalize[path].normalized = true; - } else if (isSelectBoxesComponent(component)) { - set(data, path, normalizeSelectBoxesComponentValue(value)); - scope.normalize[path].normalized = true; - } else if (isTagsComponent(component)) { - set(data, path, normalizeTagsComponentValue(component, value)); - scope.normalize[path].normalized = true; - } else if (isTextFieldComponent(component)) { - set(data, path, normalizeTextFieldComponentValue(component, defaultValues, value, path)); - scope.normalize[path].normalized = true; - } else if (isTimeComponent(component)) { - set(data, path, normalizeTimeComponentValue(component, value)); - scope.normalize[path].normalized = true; - } else if (isNumberComponent(component)) { - set(data, path, normalizeNumberComponentValue(component, value)); - scope.normalize[path].normalized = true; - } - - // Next perform component-type-agnostic transformations (i.e. super()) - if (component.multiple && !Array.isArray(value)) { - set(data, path, value ? [value] : []); - scope.normalize[path].normalized = true; + const { component, form, scope, path, data, value } = context; + if (!scope.normalize) { + scope.normalize = {}; + } + const { defaultValues } = scope; + scope.normalize[path] = { + type: component.type, + normalized: false, + }; + // First check for component-type-specific transformations + if (isAddressComponent(component)) { + set(data, path, normalizeAddressComponentValue(component, value)); + scope.normalize[path].normalized = true; + } else if (isDayComponent(component)) { + set(data, path, normalizeDayComponentValue(component, form, value)); + scope.normalize[path].normalized = true; + } else if (isEmailComponent(component)) { + if (value && typeof value === 'string') { + set(data, path, value.toLowerCase()); + scope.normalize[path].normalized = true; } + } else if (isRadioComponent(component)) { + set(data, path, normalizeRadioComponentValue(value, component.dataType)); + scope.normalize[path].normalized = true; + } else if (isSelectComponent(component)) { + set(data, path, normalizeSelectComponentValue(component, value)); + scope.normalize[path].normalized = true; + } else if (isSelectBoxesComponent(component)) { + set(data, path, normalizeSelectBoxesComponentValue(value)); + scope.normalize[path].normalized = true; + } else if (isTagsComponent(component)) { + set(data, path, normalizeTagsComponentValue(component, value)); + scope.normalize[path].normalized = true; + } else if (isTextFieldComponent(component)) { + set(data, path, normalizeTextFieldComponentValue(component, defaultValues, value, path)); + scope.normalize[path].normalized = true; + } else if (isTimeComponent(component)) { + set(data, path, normalizeTimeComponentValue(component, value)); + scope.normalize[path].normalized = true; + } else if (isNumberComponent(component)) { + set(data, path, normalizeNumberComponentValue(component, value)); + scope.normalize[path].normalized = true; + } + + // Next perform component-type-agnostic transformations (i.e. super()) + if (component.multiple && !Array.isArray(value)) { + set(data, path, value ? [value] : []); + scope.normalize[path].normalized = true; + } }; export const normalizeProcessInfo: ProcessorInfo, void> = { - name: 'normalize', - shouldProcess: () => true, - process: normalizeProcess, - processSync: normalizeProcessSync -} + name: 'normalize', + shouldProcess: () => true, + process: normalizeProcess, + processSync: normalizeProcessSync, +}; diff --git a/src/process/populate/__tests__/populate.test.ts b/src/process/populate/__tests__/populate.test.ts index 67172e14..f6f81e6c 100644 --- a/src/process/populate/__tests__/populate.test.ts +++ b/src/process/populate/__tests__/populate.test.ts @@ -1,62 +1,60 @@ import { expect } from 'chai'; -import { processSync } from '../../process' +import { processSync } from '../../process'; import { populateProcessInfo } from '../index'; import { PopulateScope, ProcessContext } from 'types'; const processForm = async (form: any, submission: any) => { - const context: ProcessContext = { - processors: [populateProcessInfo], - components: form.components, - data: submission.data, - scope: { data: submission.data } - }; - await processSync(context); - return context; + const context: ProcessContext = { + processors: [populateProcessInfo], + components: form.components, + data: submission.data, + scope: { data: submission.data }, + }; + await processSync(context); + return context; }; -describe('Populate processor', () => { - it('Should Populate a Data Grid with some Text fields', async () => { - const form = { - components: [ - { - type: 'datagrid', - key: 'grid', - components: [ - { - type: 'textfield', - key: 'a' - }, - { - type: 'textfield', - key: 'b' - }, - { - type: 'textfield', - key: 'c' - } - ] - } - ] - }; - - const submission = {data: {}}; - const context: ProcessContext = await processForm(form, submission); - expect(context.data).to.deep.equal({ - grid: [ - {} - ] - }); - context.scope.row.a = 'foo'; - context.scope.row.b = 'bar'; - context.scope.row.c = 'baz'; - expect(context.data).to.deep.equal({ - grid: [ - { - a: 'foo', - b: 'bar', - c: 'baz' - } - ] - }); +describe('Populate processor', function () { + it('Should Populate a Data Grid with some Text fields', async function () { + const form = { + components: [ + { + type: 'datagrid', + key: 'grid', + components: [ + { + type: 'textfield', + key: 'a', + }, + { + type: 'textfield', + key: 'b', + }, + { + type: 'textfield', + key: 'c', + }, + ], + }, + ], + }; + + const submission = { data: {} }; + const context: ProcessContext = await processForm(form, submission); + expect(context.data).to.deep.equal({ + grid: [{}], + }); + context.scope.row.a = 'foo'; + context.scope.row.b = 'bar'; + context.scope.row.c = 'baz'; + expect(context.data).to.deep.equal({ + grid: [ + { + a: 'foo', + b: 'bar', + c: 'baz', + }, + ], }); -}); \ No newline at end of file + }); +}); diff --git a/src/process/populate/index.ts b/src/process/populate/index.ts index f336106c..40ce6916 100644 --- a/src/process/populate/index.ts +++ b/src/process/populate/index.ts @@ -4,39 +4,38 @@ import { componentPath, getContextualRowPath, getModelType } from 'utils/formUti // This processor ensures that a "linked" row context is provided to every component. export const populateProcessSync: ProcessorFnSync = (context: PopulateContext) => { - const { component, path, scope } = 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]; - 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); - scope.populated.push({ - path, - row: get(data, compDataPath) - }); - } - break; - } - + const { component, path, scope } = 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]; + 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); + scope.populated.push({ + path, + row: get(data, compDataPath), + }); + } + break; + } }; export const populateProcessInfo = { - name: 'populate', - shouldProcess: (context: PopulateContext) => true, - processSync: populateProcessSync, + name: 'populate', + shouldProcess: () => true, + processSync: populateProcessSync, }; diff --git a/src/process/process.ts b/src/process/process.ts index f688d664..cab0e157 100644 --- a/src/process/process.ts +++ b/src/process/process.ts @@ -1,10 +1,4 @@ -import { - EachComponentDataCallback, - ProcessContext, - ProcessTarget, - ProcessorInfo, - ProcessorScope, -} from 'types'; +import { ProcessContext, ProcessTarget, ProcessorInfo, ProcessorScope } from 'types'; import { eachComponentData, eachComponentDataAsync } from 'utils/formUtil'; import { processOne, processOneSync } from './processOne'; import { @@ -32,7 +26,7 @@ import { clearHiddenProcessInfo } from './clearHidden'; import { hideChildrenProcessorInfo } from './hideChildren'; export async function process( - context: ProcessContext + context: ProcessContext, ): Promise { const { instances, components, data, scope, flat, processors } = context; @@ -53,7 +47,7 @@ export async function process( row, index, instance: instances ? instances[path] : undefined, - parent + parent, }); if (flat) { return true; @@ -62,7 +56,7 @@ export async function process( (scope as ProcessorScope).noRecurse = false; return true; } - } + }, ); for (let i = 0; i < processors?.length; i++) { const processor = processors[i]; @@ -73,9 +67,7 @@ export async function process( return scope; } -export function processSync( - context: ProcessContext -): ProcessScope { +export function processSync(context: ProcessContext): ProcessScope { const { instances, components, data, scope, flat, processors } = context; eachComponentData( @@ -95,7 +87,7 @@ export function processSync( row, index, instance: instances ? instances[path] : undefined, - parent + parent, }); if (flat) { return true; @@ -104,7 +96,7 @@ export function processSync( (scope as ProcessorScope).noRecurse = false; return true; } - } + }, ); for (let i = 0; i < processors?.length; i++) { const processor = processors[i]; @@ -132,7 +124,7 @@ export const ProcessorMap: Record> = { validate: validateProcessInfo, validateCustom: validateCustomProcessInfo, validateServer: validateServerProcessInfo, - hideChildren: hideChildrenProcessorInfo + hideChildren: hideChildrenProcessorInfo, }; export const ProcessTargets: ProcessTarget = { diff --git a/src/process/processOne.ts b/src/process/processOne.ts index 59654851..941e8ac2 100644 --- a/src/process/processOne.ts +++ b/src/process/processOne.ts @@ -1,63 +1,63 @@ -import { get, set } from "lodash"; -import { Component, ProcessorsContext, ProcessorType } from "types"; -import { getComponentKey } from "utils/formUtil"; -import { resetEphemeralState } from "utils"; +import { get, set } from 'lodash'; +import { Component, ProcessorsContext, ProcessorType } from 'types'; +import { getComponentKey } from 'utils/formUtil'; +import { resetEphemeralState } from 'utils'; export function dataValue(component: Component, row: any) { - const key = getComponentKey(component); - return key ? get(row, key) : undefined; + const key = getComponentKey(component); + return key ? get(row, key) : undefined; } export async function processOne(context: ProcessorsContext) { - const { processors, component } = context; - // Create a getter for `value` that is always derived from the current data object - if (typeof context.value === 'undefined') { - Object.defineProperty(context, 'value', { - enumerable: true, - get() { - return get(context.data, context.path); - }, - set(newValue: any) { - set(context.data, context.path, newValue); - } - }); - } - // If the component has ephemeral state, then we need to reset the ephemeral state in case this is e.g. a data grid, in which each row needs to be validated independently - resetEphemeralState(component); - if (!context.row) { - return; - } - context.processor = ProcessorType.Custom; - for (const processor of processors) { - if (processor?.process) { - await processor.process(context); - } + const { processors, component } = context; + // Create a getter for `value` that is always derived from the current data object + if (typeof context.value === 'undefined') { + Object.defineProperty(context, 'value', { + enumerable: true, + get() { + return get(context.data, context.path); + }, + set(newValue: any) { + set(context.data, context.path, newValue); + }, + }); + } + // If the component has ephemeral state, then we need to reset the ephemeral state in case this is e.g. a data grid, in which each row needs to be validated independently + resetEphemeralState(component); + if (!context.row) { + return; + } + context.processor = ProcessorType.Custom; + for (const processor of processors) { + if (processor?.process) { + await processor.process(context); } + } } export function processOneSync(context: ProcessorsContext) { - const { processors, component } = context; - // Create a getter for `value` that is always derived from the current data object - if (typeof context.value === 'undefined') { - Object.defineProperty(context, 'value', { - enumerable: true, - get() { - return get(context.data, context.path); - }, - set(newValue: any) { - set(context.data, context.path, newValue); - } - }); - } - // If the component has ephemeral state, then we need to reset the ephemeral state in case this is e.g. a data grid, in which each row needs to be validated independently - resetEphemeralState(component); - if (!context.row) { - return; - } - context.processor = ProcessorType.Custom; - for (const processor of processors) { - if (processor?.processSync) { - processor.processSync(context); - } + const { processors, component } = context; + // Create a getter for `value` that is always derived from the current data object + if (typeof context.value === 'undefined') { + Object.defineProperty(context, 'value', { + enumerable: true, + get() { + return get(context.data, context.path); + }, + set(newValue: any) { + set(context.data, context.path, newValue); + }, + }); + } + // If the component has ephemeral state, then we need to reset the ephemeral state in case this is e.g. a data grid, in which each row needs to be validated independently + resetEphemeralState(component); + if (!context.row) { + return; + } + context.processor = ProcessorType.Custom; + for (const processor of processors) { + if (processor?.processSync) { + processor.processSync(context); } + } } diff --git a/src/process/validation/__tests__/Validator.test.ts b/src/process/validation/__tests__/Validator.test.ts index d7f22d87..fbe12c55 100644 --- a/src/process/validation/__tests__/Validator.test.ts +++ b/src/process/validation/__tests__/Validator.test.ts @@ -1,39 +1,41 @@ import { get } from 'lodash'; import { expect } from 'chai'; import { validateProcess } from '../index'; -import { rules } from "../rules"; +import { rules } from '../rules'; import { simpleForm } from './fixtures/forms'; import { ProcessorType, ValidationScope } from 'types'; -it('Validator will throw the correct errors given a flat components array', async () => { +describe('Validator', function () { + it('Validator will throw the correct errors given a flat components array', async function () { let errors: string[] = []; const data = { - requiredField: '', - maximumWords: - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', - minimumWords: 'Hello', - email: 'brendanb', - url: 'htpigoogle', - inputMask: 'hello, world', - time: ['12:00:00', '11:00'], // one of the values is provided in incorrect format (format instead dataFormat) - submit: false, + requiredField: '', + maximumWords: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + minimumWords: 'Hello', + email: 'brendanb', + url: 'htpigoogle', + inputMask: 'hello, world', + time: ['12:00:00', '11:00'], // one of the values is provided in incorrect format (format instead dataFormat) + submit: false, }; - for (let component of simpleForm.components) { - const path = component.key; - const scope: ValidationScope = { errors: [] }; - await validateProcess({ - component, - scope, - data, - row: data, - path, - value: get(data, component.key), - processor: ProcessorType.Validate, - rules, - }); - if (scope.errors) { - errors = [...errors, ...scope.errors.map((error) => error.errorKeyOrMessage)]; - } + for (const component of simpleForm.components) { + const path = component.key; + const scope: ValidationScope = { errors: [] }; + await validateProcess({ + component, + scope, + data, + row: data, + path, + value: get(data, component.key), + processor: ProcessorType.Validate, + rules, + }); + if (scope.errors) { + errors = [...errors, ...scope.errors.map((error) => error.errorKeyOrMessage)]; + } } expect(errors).to.have.length(7); + }); }); diff --git a/src/process/validation/__tests__/fixtures/components.ts b/src/process/validation/__tests__/fixtures/components.ts index ec2611eb..5c441c16 100644 --- a/src/process/validation/__tests__/fixtures/components.ts +++ b/src/process/validation/__tests__/fixtures/components.ts @@ -1,202 +1,202 @@ import { - DateTimeComponent, - DayComponent, - NumberComponent, - RadioComponent, - SelectBoxesComponent, - SelectComponentOptions, - TextFieldComponent, + DateTimeComponent, + DayComponent, + NumberComponent, + RadioComponent, + SelectBoxesComponent, + SelectComponentOptions, + TextFieldComponent, } from 'types/Component'; export const simpleTextField: TextFieldComponent = { - type: 'textField', - label: 'Simple Text Field', - input: true, - tableView: true, - key: 'component', + type: 'textField', + label: 'Simple Text Field', + input: true, + tableView: true, + key: 'component', }; export const simpleDateTimeField: DateTimeComponent = { - tableView: false, - label: 'Simple Date/Time', - datePicker: { - disableWeekends: false, - disableWeekdays: false, - }, - enableMinDateInput: false, - enableMaxDateInput: false, - enableDate: true, - key: 'component', - type: 'datetime', - input: true, - widget: { - type: 'calendar', - displayInTimezone: 'viewer', - locale: 'en', - useLocaleSettings: false, - allowInput: true, - mode: 'single', - enableTime: true, - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - hourIncrement: 1, - minuteIncrement: 1, - time_24hr: false, - disableWeekends: false, - disableWeekdays: false, - }, + tableView: false, + label: 'Simple Date/Time', + datePicker: { + disableWeekends: false, + disableWeekdays: false, + }, + enableMinDateInput: false, + enableMaxDateInput: false, + enableDate: true, + key: 'component', + type: 'datetime', + input: true, + widget: { + type: 'calendar', + displayInTimezone: 'viewer', + locale: 'en', + useLocaleSettings: false, + allowInput: true, + mode: 'single', + enableTime: true, + noCalendar: false, + format: 'yyyy-MM-dd hh:mm a', + hourIncrement: 1, + minuteIncrement: 1, + time_24hr: false, + disableWeekends: false, + disableWeekdays: false, + }, }; export const simpleDayField: DayComponent = { - label: 'Simple Day', - hideInputLabels: false, - inputsLabelPosition: 'top', - useLocaleSettings: false, - tableView: false, - fields: { - day: { - hide: false, - }, - month: { - hide: false, - }, - year: { - hide: false, - }, + label: 'Simple Day', + hideInputLabels: false, + inputsLabelPosition: 'top', + useLocaleSettings: false, + tableView: false, + fields: { + day: { + hide: false, }, - key: 'component', - type: 'day', - input: true, - defaultValue: '00/00/0000', + month: { + hide: false, + }, + year: { + hide: false, + }, + }, + key: 'component', + type: 'day', + input: true, + defaultValue: '00/00/0000', }; export const calendarTextField: TextFieldComponent = { - label: 'Text Field', - widget: { - type: 'calendar', - altInput: true, - allowInput: true, - clickOpens: true, - // enableDate: true, - enableTime: true, - mode: 'single', - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-ddTHH:mm:ssZ', - useLocaleSettings: false, - hourIncrement: 1, - minuteIncrement: 5, - time_24hr: false, - saveAs: 'text', - displayInTimezone: 'viewer', - locale: 'en', - }, - tableView: true, - key: 'component', - type: 'textfield', - input: true, + label: 'Text Field', + widget: { + type: 'calendar', + altInput: true, + allowInput: true, + clickOpens: true, + // enableDate: true, + enableTime: true, + mode: 'single', + noCalendar: false, + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-ddTHH:mm:ssZ', + useLocaleSettings: false, + hourIncrement: 1, + minuteIncrement: 5, + time_24hr: false, + saveAs: 'text', + displayInTimezone: 'viewer', + locale: 'en', + }, + tableView: true, + key: 'component', + type: 'textfield', + input: true, }; export const simpleEmailField = { - label: 'Email', - tableView: true, - key: 'component', - type: 'email', - input: true, + label: 'Email', + tableView: true, + key: 'component', + type: 'email', + input: true, }; export const simpleSelectBoxes: SelectBoxesComponent = { - label: 'Select Boxes', - optionsLabelPosition: 'right', - tableView: false, - values: [ - { - label: 'foo', - value: 'foo', - }, - { - label: 'bar', - value: 'bar', - }, - { - label: 'baz', - value: 'baz', - }, - { - label: 'biz', - value: 'biz', - }, - ], - validate: { - maxSelectedCount: 3, + label: 'Select Boxes', + optionsLabelPosition: 'right', + tableView: false, + values: [ + { + label: 'foo', + value: 'foo', }, - key: 'component', - type: 'selectboxes', - input: true, - inputType: 'checkbox', + { + label: 'bar', + value: 'bar', + }, + { + label: 'baz', + value: 'baz', + }, + { + label: 'biz', + value: 'biz', + }, + ], + validate: { + maxSelectedCount: 3, + }, + key: 'component', + type: 'selectboxes', + input: true, + inputType: 'checkbox', }; export const simpleNumberField: NumberComponent = { - label: 'Number', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - truncateMultipleSpaces: false, - key: 'component', - type: 'number', - input: true, + label: 'Number', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + truncateMultipleSpaces: false, + key: 'component', + type: 'number', + input: true, }; export const simpleUrlField = { - label: 'Url', - tableView: true, - key: 'component', - type: 'url', - input: true, + label: 'Url', + tableView: true, + key: 'component', + type: 'url', + input: true, }; export const simpleSelectOptions: SelectComponentOptions = { - label: 'Select', - widget: 'choicesjs', - tableView: true, - key: 'component', - template: '{{ item.label }}', - type: 'select', - input: true, - lazyLoad: false, - disableLimit: false, + label: 'Select', + widget: 'choicesjs', + tableView: true, + key: 'component', + template: '{{ item.label }}', + type: 'select', + input: true, + lazyLoad: false, + disableLimit: false, }; export const simpleRadioField: RadioComponent = { - label: 'Radio', - optionsLabelPosition: 'right', - inline: false, - tableView: false, - values: [ - { - label: 'foo', - value: 'foo', - shortcut: '', - }, - { - label: 'bar', - value: 'bar', - shortcut: '', - }, - { - label: 'baz', - value: 'baz', - shortcut: '', - }, - { - label: 'biz', - value: 'biz', - shortcut: '', - }, - ], - key: 'component', - type: 'radio', - input: true, + label: 'Radio', + optionsLabelPosition: 'right', + inline: false, + tableView: false, + values: [ + { + label: 'foo', + value: 'foo', + shortcut: '', + }, + { + label: 'bar', + value: 'bar', + shortcut: '', + }, + { + label: 'baz', + value: 'baz', + shortcut: '', + }, + { + label: 'biz', + value: 'biz', + shortcut: '', + }, + ], + key: 'component', + type: 'radio', + input: true, }; diff --git a/src/process/validation/__tests__/fixtures/forms.ts b/src/process/validation/__tests__/fixtures/forms.ts index 37717dcc..f6718e6d 100644 --- a/src/process/validation/__tests__/fixtures/forms.ts +++ b/src/process/validation/__tests__/fixtures/forms.ts @@ -1,359 +1,1799 @@ export const w4 = { - _id: '5994b43413a5f60007084c9f', - machineName: 'examples:w4', - modified: '2023-02-13T18:59:11.166Z', - title: 'W4', - display: 'pdf', - settings: { - pdf: { - id: '1ec0f8ee-6685-5d98-a847-26f67b67d6f0', - src: 'https://files.form.io/pdf/5692b91fd1028f01000407e3/file/1ec0f8ee-6685-5d98-a847-26f67b67d6f0', - }, + _id: '5994b43413a5f60007084c9f', + machineName: 'examples:w4', + modified: '2023-02-13T18:59:11.166Z', + title: 'W4', + display: 'pdf', + settings: { + pdf: { + id: '1ec0f8ee-6685-5d98-a847-26f67b67d6f0', + src: 'https://files.form.io/pdf/5692b91fd1028f01000407e3/file/1ec0f8ee-6685-5d98-a847-26f67b67d6f0', + }, + }, + name: 'w4', + path: 'w4', + project: '5692b91fd1028f01000407e3', + created: '2017-08-16T21:08:04.689Z', + components: [ + { + input: true, + tableView: true, + label: 'Office Code', + key: 'officeCode', + type: 'textfield', + overlay: { width: 121, height: 21, left: 656.344, top: 1319, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'e279pgyh', + }, + { + input: true, + tableView: true, + label: 'Employers Name and Address', + key: 'employersName', + type: 'textfield', + overlay: { + width: 570, + height: 21, + left: 79.34379999999999, + top: 1320, + page: 1, + style: '', + }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'ebh0ey', + }, + { + input: true, + tableView: true, + label: 'date', + key: 'date', + datePicker: { + datepickerMode: 'day', + showWeeks: true, + startingDay: 0, + initDate: '', + minMode: 'day', + maxMode: 'year', + yearRows: 4, + yearColumns: 5, + minDate: null, + maxDate: null, + }, + type: 'datetime', + overlay: { width: 176, height: 22, left: 842.344, top: 1275, page: 1, style: '' }, + widget: { + type: 'calendar', + displayInTimezone: 'viewer', + submissionTimezone: 'Europe/Paris', + locale: 'en', + useLocaleSettings: false, + allowInput: true, + mode: 'single', + enableTime: true, + noCalendar: false, + format: 'yyyy-MM-dd hh:mm a', + hourIncrement: 1, + minuteIncrement: 1, + time_24hr: false, + minDate: null, + maxDate: null, + }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: '', + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + format: 'yyyy-MM-dd hh:mm a', + useLocaleSettings: false, + allowInput: true, + enableDate: true, + enableTime: true, + defaultDate: '', + displayInTimezone: 'viewer', + timezone: '', + datepickerMode: 'day', + timePicker: { + hourStep: 1, + minuteStep: 1, + showMeridian: true, + readonlyInput: false, + mousewheel: true, + arrowkeys: true, + }, + customOptions: {}, + id: 'e38qzkb', + }, + { + input: true, + tableView: true, + label: 'Signature', + key: 'signature', + type: 'signature', + overlay: { width: 437, height: 41, left: 347.344, top: 1257, page: 1, style: '' }, + hideLabel: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + footer: 'Sign above', + width: '100%', + height: '150px', + penColor: 'black', + backgroundColor: 'rgb(245,245,235)', + minWidth: '0.5', + maxWidth: '2.5', + keepOverlayRatio: true, + id: 'ervvnoe', + }, + { + input: true, + tableView: true, + label: 'City, State, Zip', + key: 'cityStateZip', + type: 'textfield', + overlay: { width: 465, height: 21, left: 80.3438, top: 1084, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'e4x5zp', + }, + { + hideLabel: true, + overlay: { + page: 1, + top: 1027.8, + left: 730.538, + height: 12.75628779296875, + width: 11.400024414062523, + style: '', + }, + type: 'checkbox', + value: 'marriedsingle', + name: 'status', + defaultValue: false, + key: 'marriedButSingle', + datagridLabel: true, + label: 'Married But Single', + tableView: true, + inputType: 'radio', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'right', + description: '', + errorLabel: '', + tooltip: '', + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'eg81i4m', + }, + { + hideLabel: true, + overlay: { + page: 1, + top: 1027.4, + left: 652.938, + height: 13.618787792968659, + width: 13.400012207031228, + style: '', + }, + type: 'checkbox', + value: 'married', + name: 'status', + defaultValue: false, + key: 'married', + datagridLabel: true, + label: 'Married', + tableView: true, + inputType: 'radio', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'right', + description: '', + errorLabel: '', + tooltip: '', + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'efb089c', + }, + { + hideLabel: true, + overlay: { + page: 1, + top: 1027, + left: 576.538, + height: 13.88128779296875, + width: 13.400012207031205, + style: '', + }, + type: 'checkbox', + value: 'single', + name: 'status', + defaultValue: false, + key: 'single', + datagridLabel: true, + label: 'Single', + tableView: true, + inputType: 'radio', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'right', + description: '', + errorLabel: '', + tooltip: '', + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'emtvqvgq', + }, + { + overlay: { + page: 1, + top: 1044.2255555555555, + left: 81.30207777777777, + height: 21.10074501953125, + width: 466.72555555555556, + style: '', + }, + type: 'textfield', + key: 'homeAddress', + label: 'Home Address', + tableView: true, + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'ewtco6b', + }, + { + overlay: { + page: 1, + top: 998.6667777777777, + left: 789.0803333333333, + height: 23.47576724175342, + width: 234.0871314561631, + style: '', + }, + type: 'textfield', + key: 'ssn', + label: 'ssn', + inputMask: '999-99-9999', + tableView: true, + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'edz921k', + }, + { + overlay: { + page: 1, + top: 999.2222222222222, + left: 387.4138888888889, + height: 22.095556130642336, + width: 389.90500508626303, + style: '', + }, + type: 'textfield', + key: 'lastName', + label: 'Last Name', + tableView: true, + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'e2de7sa', + }, + { + overlay: { + page: 1, + top: 998.6664444444444, + left: 81.85761111111108, + height: 23.24826724175342, + width: 299.9064457160102, + style: '', + }, + type: 'textfield', + key: 'firstName', + label: 'First Name', + tableView: true, + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'eq3xm7d', + }, + { + overlay: { + page: 1, + top: 750.3336666666667, + left: 972.9684444444445, + height: '18', + width: '50', + style: '', + }, + type: 'textfield', + key: 'h', + label: 'H', + tableView: true, + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'ej8thdm', + }, + { + input: true, + tableView: true, + label: 'G', + key: 'g', + type: 'textfield', + overlay: { width: '50', height: '18', left: 973.172, top: 726.5, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'esj0u5e', + }, + { + input: true, + tableView: true, + label: 'F', + key: 'f', + type: 'textfield', + overlay: { width: '50', height: '18', left: 973.172, top: 621.5, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'e0kdkzp', }, - name: 'w4', - path: 'w4', - project: '5692b91fd1028f01000407e3', - created: '2017-08-16T21:08:04.689Z', - components: [ + { + input: true, + tableView: true, + label: 'E', + key: 'e', + type: 'textfield', + overlay: { width: '50', height: '18', left: 973.172, top: 599.5, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'e4wp06', + }, + { + input: true, + tableView: true, + label: 'D', + key: 'd', + type: 'textfield', + overlay: { width: '50', height: '18', left: 972.672, top: 577.5, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'evg04s8', + }, + { + input: true, + tableView: true, + label: 'C', + key: 'c', + type: 'textfield', + overlay: { width: '50', height: '18', left: 972.672, top: 556.5, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'e953emh', + }, + { + input: true, + tableView: true, + label: 'B', + key: 'b', + type: 'textfield', + overlay: { width: '50', height: '18', left: 972.672, top: 493, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'e2l0zzm', + }, + { + input: true, + tableView: true, + label: 'A', + key: 'a', + type: 'textfield', + overlay: { width: '50', height: '18', left: 972.469, top: 449.375, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'egw3xvl', + }, + { + input: true, + label: 'Submit', + tableView: false, + key: 'submit', + type: 'button', + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + size: 'md', + leftIcon: '', + rightIcon: '', + block: false, + action: 'submit', + disableOnInvalid: false, + theme: 'primary', + id: 'etn79o', + }, + ], + owner: '553dbfc08d22d5cb1a7024f2', + submissionAccess: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { roles: [], type: 'read_all' }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + access: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { + roles: ['5692b920d1028f01000407e4', '5692b920d1028f01000407e5', '5692b920d1028f01000407e6'], + type: 'read_all', + }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + tags: [], + type: 'form', + _vid: 0, + revisions: '', +}; + +export const example = { + _id: '57aa1d2a5b7a477b002717fe', + machineName: 'examples:example', + modified: '2022-12-09T17:14:46.932Z', + title: 'Example', + display: 'form', + type: 'form', + name: 'example', + path: 'example', + project: '5692b91fd1028f01000407e3', + created: '2016-08-09T18:12:58.126Z', + components: [ + { + input: false, + html: '

Form.io Example Form

\n\n

This is a dynamically rendered JSON form built with Form.io. Using a simple drag-and-drop form builder, you can create any form that includes e-signatures, wysiwyg editors, date fields, layout components, data grids, surveys, etc.

\n', + type: 'content', + conditional: { show: '', when: null, eq: '' }, + key: 'content', + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + tableView: false, + modalEdit: false, + label: 'Content', + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + id: 'e4w5wnn', + addons: [], + }, + { + input: false, + columns: [ { - input: true, - tableView: true, - label: 'Office Code', - key: 'officeCode', - type: 'textfield', - overlay: { width: 121, height: 21, left: 656.344, top: 1319, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + components: [ + { + tabindex: '1', + tags: [], + clearOnHide: true, + hidden: false, + input: true, + tableView: true, + inputType: 'text', + inputMask: '', + label: 'First Name', + key: 'firstName', + placeholder: 'Enter your first name', + prefix: '', + suffix: '', + multiple: false, + defaultValue: '', + protected: false, + unique: false, + persistent: true, + validate: { required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, minLength: '', maxLength: '', pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e279pgyh', - }, - { - input: true, - tableView: true, - label: 'Employers Name and Address', - key: 'employersName', - type: 'textfield', - overlay: { - width: 570, - height: 21, - left: 79.34379999999999, - top: 1320, - page: 1, - style: '', - }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, custom: '', customPrivate: false, strictDateValidation: false, multiple: false, unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'ebh0ey', - }, - { - input: true, - tableView: true, - label: 'date', - key: 'date', - datePicker: { - datepickerMode: 'day', - showWeeks: true, - startingDay: 0, - initDate: '', - minMode: 'day', - maxMode: 'year', - yearRows: 4, - yearColumns: 5, - minDate: null, - maxDate: null, - }, - type: 'datetime', - overlay: { width: 176, height: 22, left: 842.344, top: 1275, page: 1, style: '' }, - widget: { - type: 'calendar', - displayInTimezone: 'viewer', - submissionTimezone: 'Europe/Paris', - locale: 'en', - useLocaleSettings: false, - allowInput: true, - mode: 'single', - enableTime: true, - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - hourIncrement: 1, - minuteIncrement: 1, - time_24hr: false, - minDate: null, - maxDate: null, + }, + conditional: { show: '', when: null, eq: '' }, + type: 'textfield', + customClass: '', + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + mask: false, + inputFormat: 'plain', + spellcheck: true, + id: 'ek1pl3', + addons: [], + displayMask: '', + truncateMultipleSpaces: false, }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: '', - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - attributes: {}, - validateOn: 'change', - validate: { + { + tabindex: '3', + tags: [], + clearOnHide: true, + hidden: false, + input: true, + tableView: true, + inputType: 'email', + label: 'Email', + key: 'email', + placeholder: 'Enter your email address', + prefix: '', + suffix: '', + defaultValue: '', + protected: false, + unique: false, + persistent: true, + type: 'email', + conditional: { show: '', when: null, eq: '' }, + kickbox: { enabled: false }, + customClass: '', + multiple: false, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, strictDateValidation: false, multiple: false, unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + mask: false, + inputFormat: 'plain', + inputMask: '', + spellcheck: true, + id: 'en2328', + addons: [], + displayMask: '', + truncateMultipleSpaces: false, }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - format: 'yyyy-MM-dd hh:mm a', - useLocaleSettings: false, - allowInput: true, - enableDate: true, - enableTime: true, - defaultDate: '', - displayInTimezone: 'viewer', - timezone: '', - datepickerMode: 'day', - timePicker: { - hourStep: 1, - minuteStep: 1, - showMeridian: true, - readonlyInput: false, - mousewheel: true, - arrowkeys: true, - }, - customOptions: {}, - id: 'e38qzkb', + ], + width: 6, + offset: 0, + push: 0, + pull: 0, + size: 'md', + currentWidth: 6, }, { - input: true, - tableView: true, - label: 'Signature', - key: 'signature', - type: 'signature', - overlay: { width: 437, height: 41, left: 347.344, top: 1257, page: 1, style: '' }, - hideLabel: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + components: [ + { + tabindex: '2', + tags: [], + clearOnHide: true, + hidden: false, + input: true, + tableView: true, + inputType: 'text', + inputMask: '', + label: 'Last Name', + key: 'lastName', + placeholder: 'Enter your last name', + prefix: '', + suffix: '', + multiple: false, + defaultValue: '', + protected: false, + unique: false, + persistent: true, + validate: { required: false, + minLength: '', + maxLength: '', + pattern: '', custom: '', customPrivate: false, strictDateValidation: false, multiple: false, unique: false, + }, + conditional: { show: '', when: null, eq: '' }, + type: 'textfield', + customClass: '', + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + mask: false, + inputFormat: 'plain', + spellcheck: true, + id: 'ex6xzd', + addons: [], + displayMask: '', + truncateMultipleSpaces: false, }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - footer: 'Sign above', - width: '100%', - height: '150px', - penColor: 'black', - backgroundColor: 'rgb(245,245,235)', - minWidth: '0.5', - maxWidth: '2.5', - keepOverlayRatio: true, - id: 'ervvnoe', - }, - { - input: true, - tableView: true, - label: 'City, State, Zip', - key: 'cityStateZip', - type: 'textfield', - overlay: { width: 465, height: 21, left: 80.3438, top: 1084, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + { + tabindex: '4', + tags: [], + clearOnHide: true, + hidden: false, + input: true, + tableView: true, + inputMask: '(999) 999-9999', + label: 'Phone Number', + key: 'phoneNumber', + placeholder: 'Enter your phone number', + prefix: '', + suffix: '', + multiple: false, + protected: false, + unique: false, + persistent: true, + defaultValue: '', + validate: { required: false, custom: '', customPrivate: false, @@ -363,483 +1803,1349 @@ export const w4 = { minLength: '', maxLength: '', pattern: '', + }, + type: 'phoneNumber', + conditional: { show: '', when: null, eq: '' }, + customClass: '', + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + mask: false, + inputType: 'tel', + inputFormat: 'plain', + spellcheck: true, + inputMode: 'decimal', + id: 'ecee6s', + addons: [], + displayMask: '', + truncateMultipleSpaces: false, }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e4x5zp', + ], + width: 6, + offset: 0, + push: 0, + pull: 0, + size: 'md', + currentWidth: 6, }, + ], + type: 'columns', + conditional: { show: '', when: null, eq: '' }, + key: 'columns', + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: false, + refreshOn: '', + redrawOn: '', + tableView: false, + modalEdit: false, + label: 'Columns', + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + tree: false, + autoAdjust: false, + id: 'e2i9r0c', + addons: [], + lazyLoad: false, + }, + { + tabindex: '5', + tags: [], + clearOnHide: true, + hidden: false, + input: true, + tableView: true, + label: 'Survey', + key: 'survey', + questions: [ { - hideLabel: true, - overlay: { - page: 1, - top: 1027.8, - left: 730.538, - height: 12.75628779296875, - width: 11.400024414062523, - style: '', - }, - type: 'checkbox', - value: 'marriedsingle', - name: 'status', - defaultValue: false, - key: 'marriedButSingle', - datagridLabel: true, - label: 'Married But Single', - tableView: true, - inputType: 'radio', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + value: 'howWouldYouRateTheFormIoPlatform', + label: 'How would you rate the Form.io platform?', + }, + { value: 'howWasCustomerSupport', label: 'How was Customer Support?' }, + { value: 'overallExperience', label: 'Overall Experience?' }, + ], + values: [ + { value: 'excellent', label: 'Excellent' }, + { value: 'great', label: 'Great' }, + { value: 'good', label: 'Good' }, + { value: 'average', label: 'Average' }, + { value: 'poor', label: 'Poor' }, + ], + defaultValue: '', + protected: false, + persistent: true, + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + type: 'survey', + conditional: { show: '', when: null, eq: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + unique: false, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + id: 'ek3vrnp', + addons: [], + }, + { + tags: [], + clearOnHide: true, + hidden: false, + input: true, + tableView: true, + label: 'Signature', + key: 'signature', + placeholder: '', + footer: 'Sign above', + width: '100%', + height: '150px', + penColor: 'black', + backgroundColor: 'rgb(245,245,235)', + minWidth: '0.5', + maxWidth: '2.5', + protected: false, + persistent: true, + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + type: 'signature', + hideLabel: true, + conditional: { show: '', when: null, eq: '' }, + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + unique: false, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + id: 'e4zac8j', + addons: [], + keepOverlayRatio: true, + }, + { + tabindex: '6', + conditional: { eq: '', when: null, show: '' }, + tags: [], + input: true, + label: 'Submit', + tableView: false, + key: 'submit', + size: 'md', + leftIcon: '', + rightIcon: '', + block: false, + action: 'submit', + disableOnInvalid: true, + theme: 'primary', + type: 'button', + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + id: 'et5j8rn', + addons: [], + }, + ], + owner: '554806425867f4ee203ea861', + submissionAccess: [ + { roles: ['5692b920d1028f01000407e6'], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { roles: [], type: 'read_all' }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + access: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { + roles: [ + '5692b920d1028f01000407e4', + '5692b920d1028f01000407e5', + '5692b920d1028f01000407e6', + '000000000000000000000000', + ], + type: 'read_all', + }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + tags: [], + _vid: 0, + revisions: '', +}; + +export const simpleForm = { + _id: '641b2ba3488ffcafa27c2e9f', + title: 'Simple Form', + name: 'simpleForm', + path: 'simpleform', + type: 'form', + display: 'form', + tags: [], + components: [ + { + label: 'Required Field', + applyMaskOn: 'change', + tableView: true, + validate: { + required: true, + }, + key: 'requiredField', + type: 'textfield', + input: true, + }, + { + label: 'Maximum Words', + applyMaskOn: 'change', + autoExpand: false, + tableView: true, + validate: { + maxWords: 4, + }, + key: 'maximumWords', + type: 'textarea', + input: true, + }, + { + label: 'Minimum Words', + applyMaskOn: 'change', + autoExpand: false, + tableView: true, + validate: { + minWords: 2, + }, + key: 'minimumWords', + type: 'textarea', + input: true, + }, + { + label: 'Email', + applyMaskOn: 'change', + tableView: true, + key: 'email', + type: 'email', + input: true, + }, + { + label: 'Url', + applyMaskOn: 'change', + tableView: true, + key: 'url', + type: 'url', + input: true, + }, + { + label: 'Input Mask', + applyMaskOn: 'change', + tableView: true, + key: 'inputMask', + type: 'phoneNumber', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { + type: 'input', + }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { + show: null, + when: null, + eq: '', + }, + overlay: { + style: '', + left: '', + top: '', + width: '', + height: '', + }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'tel', + inputFormat: 'plain', + inputMask: '(999) 999-9999', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + inputMode: 'decimal', + id: 'e8vls3a', + keyModified: true, + }, + { + label: 'Time', + type: 'time', + key: 'time', + input: true, + dataFormat: 'HH:mm:ss', + format: 'HH:mm', + multiple: true, + }, + { + type: 'button', + label: 'Submit', + key: 'submit', + disableOnInvalid: true, + input: true, + tableView: false, + }, + ], + settings: {}, + properties: {}, + project: '6419d8f2322509215938a9e6', + controller: '', + revisions: '', + submissionRevisions: '', + _vid: 0, + created: '2023-03-22T16:24:03.220Z', + modified: '2023-03-22T16:27:12.193Z', + machineName: 'qgvzeueerscrxbs:simpleForm', +}; + +export const wizard = { + _id: '578f930ef1912f8000459a50', + machineName: 'examples:wizard', + modified: '2022-11-17T20:30:28.519Z', + title: 'Wizard', + display: 'wizard', + type: 'form', + name: 'wizard', + path: 'wizard', + project: '5692b91fd1028f01000407e3', + created: '2016-07-20T15:04:46.906Z', + components: [ + { + key: 'page1', + input: false, + components: [ + { + type: 'textfield', + multiple: true, + key: 'textfieldonpage1', + label: 'Textfield on page 1', + tableView: true, + input: true, + }, + { + type: 'number', + validate: { required: true }, + defaultValue: 0, + key: 'numberField', + label: 'Number Field', + inputType: 'number', + tableView: true, + input: true, + }, + ], + title: 'First', + type: 'panel', + tableView: false, + label: 'Panel', + }, + { + tableView: false, + key: 'page2', + input: false, + components: [ + { + type: 'textfield', + validate: { required: true }, + key: 'textfieldonPage2', + label: 'Textfield on Page 2', + tableView: true, + input: true, + }, + { + input: true, + tableView: true, + label: 'Customer', + key: 'page2Customer', + placeholder: 'Select a customer', + data: { + url: 'https://examples.form.io/customer/submission', + headers: [{ value: '', key: '' }], + }, + dataSrc: 'url', + valueProperty: 'data.email', + template: '{{ item.data.firstName }} {{ item.data.lastName }}', + type: 'select', + widget: 'html5', + searchField: 'data.email', + }, + { + clearOnHide: false, + type: 'fieldset', + components: [ + { + type: 'textfield', + key: 'textfield', + label: 'Textfield', + tableView: true, + input: true, }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'eg81i4m', + ], + legend: 'FieldSet Label', + tableView: true, + input: false, + key: 'fieldSet', + label: 'Field Set', + }, + ], + title: 'Page 2', + type: 'panel', + label: 'Panel', + }, + { + type: 'panel', + components: [ + { + input: true, + tableView: true, + label: 'Text', + key: 'panelText', + validate: { required: true }, + type: 'textfield', }, { - hideLabel: true, - overlay: { - page: 1, - top: 1027.4, - left: 652.938, - height: 13.618787792968659, - width: 13.400012207031228, - style: '', + type: 'datagrid', + key: 'panelDataGrid', + label: 'Data Grid', + tableView: true, + components: [ + { + hideLabel: true, + type: 'textfield', + key: 'panelDataGridA', + label: 'A', + tableView: true, + input: true, + inDataGrid: true, }, - type: 'checkbox', - value: 'married', - name: 'status', - defaultValue: false, - key: 'married', - datagridLabel: true, - label: 'Married', - tableView: true, - inputType: 'radio', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + { + hideLabel: true, + type: 'textfield', + key: 'panelDataGridB', + label: 'B', + tableView: true, + input: true, + inDataGrid: true, + }, + { + hideLabel: true, + type: 'textfield', + key: 'panelDataGridC', + label: 'C', + tableView: true, + input: true, + inDataGrid: true, }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'efb089c', + { + hideLabel: true, + type: 'textfield', + key: 'panelDataGridD', + label: 'D', + tableView: true, + input: true, + inDataGrid: true, + }, + ], + input: true, }, { - hideLabel: true, - overlay: { - page: 1, - top: 1027, - left: 576.538, - height: 13.88128779296875, - width: 13.400012207031205, - style: '', - }, - type: 'checkbox', - value: 'single', - name: 'status', - defaultValue: false, - key: 'single', - datagridLabel: true, - label: 'Single', - tableView: true, - inputType: 'radio', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', + input: true, + tableView: true, + label: 'HTML5 Select', + key: 'panelHtml5Select', + data: { + values: [ + { value: 'orange', label: 'Orange' }, + { value: 'apple', label: 'Apple' }, + { value: 'banana', label: 'Banana' }, + { value: 'strawberry', label: 'Strawberry' }, + { value: 'kiwi', label: 'Kiwi' }, + ], + }, + widget: 'html5', + type: 'select', + }, + ], + tableView: false, + title: 'Page 3', + input: false, + key: 'panel', + label: 'Panel', + }, + { + key: 'page3', + input: false, + components: [ + { + type: 'textfield', + key: 'textfieldonPage3', + label: 'Textfield on Page 3', + tableView: true, + input: true, + }, + { + input: true, + tableView: true, + label: 'I agree to the follow the rules', + dataGridLabel: false, + key: 'page3Iagreetothefollowtherules', + defaultValue: false, + type: 'checkbox', + }, + { + input: true, + tableView: true, + label: 'Signature', + key: 'signature', + type: 'signature', + hideLabel: true, + lockKey: true, + }, + ], + title: 'Last', + type: 'panel', + tableView: false, + label: 'Panel', + }, + { + type: 'button', + disableOnInvalid: true, + key: 'submit', + tableView: false, + label: 'Submit', + input: true, + }, + ], + owner: '55673dc04f0405dd28205bb7', + submissionAccess: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { roles: ['5692b920d1028f01000407e6'], type: 'read_all' }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + access: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { + roles: ['5692b920d1028f01000407e4', '5692b920d1028f01000407e5', '5692b920d1028f01000407e6'], + type: 'read_all', + }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + tags: ['common'], + settings: { + controller: + "['$scope', function($scope) { $scope.$watch('submission.data', function(data) { console.log(data); }, true); }]", + }, + revisions: '', + _vid: 0, + controller: '', + properties: {}, +}; + +export const inlineEmbedFormPortal = { + _id: '617c032c68daf082ce063303', + type: 'form', + tags: [], + owner: '5e4aa9cf4037892ed27d5550', + components: [ + { + label: 'HTML', + tag: 'div', + attrs: [{ attr: '', value: '' }], + content: + "

Quick Inline Embed

\r\n

To quickly embed this form without using any framework, you can use the following code snippit and configure it using the Inline Embed Configuration form below.

\r\n

See our Inline Embed Documentation to know more about it.

", + refreshOnChange: false, + key: 'html1', + type: 'htmlelement', + input: false, + tableView: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'emraund', + }, + { + label: 'HTML', + tag: 'pre', + attrs: [{ attr: '', value: '' }], + content: + '', + refreshOnChange: true, + key: 'html', + type: 'htmlelement', + input: false, + tableView: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'e3wopjp', + }, + { + label: 'Copy to Clipboard', + action: 'custom', + showValidations: false, + theme: 'success', + block: true, + leftIcon: 'fa fa-copy', + tableView: false, + key: 'copyToClipboard', + type: 'button', + custom: + 'var embedCode = document.getElementById(\'embed-code\');\nif (embedCode) {\n embedCode.focus();\n embedCode.select();\n document.execCommand("copy");\n}', + input: true, + hideOnChildrenHidden: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + size: 'md', + rightIcon: '', + disableOnInvalid: false, + id: 'eq2y2ul', + }, + { + title: 'Inline Embed Configuration', + collapsible: false, + key: 'embedConfiguration', + type: 'panel', + label: 'Inline Embed Configuration', + input: false, + tableView: false, + components: [ + { + label: 'Embed Script', + customDefaultValue: "value = instance.options?.quickInlineEmbed || '';", + key: 'embed', + type: 'hidden', + tableView: true, + input: true, + mask: false, + inputType: 'text', + inputFormat: 'plain', + spellcheck: true, + hideOnChildrenHidden: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, multiple: false, - protected: false, unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'emtvqvgq', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'eq04647', }, { - overlay: { - page: 1, - top: 1044.2255555555555, - left: 81.30207777777777, - height: 21.10074501953125, - width: 466.72555555555556, - style: '', - }, - type: 'textfield', - key: 'homeAddress', - label: 'Home Address', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', + label: 'Project', + tableView: true, + key: 'project', + type: 'hidden', + input: true, + mask: false, + inputType: 'text', + inputFormat: 'plain', + spellcheck: true, + hideOnChildrenHidden: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, multiple: false, - defaultValue: null, - protected: false, unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'ewtco6b', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'eowdp4', }, { - overlay: { - page: 1, - top: 998.6667777777777, - left: 789.0803333333333, - height: 23.47576724175342, - width: 234.0871314561631, - style: '', - }, - type: 'textfield', - key: 'ssn', - label: 'ssn', - inputMask: '999-99-9999', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', + label: 'Base', + tableView: true, + key: 'base', + type: 'hidden', + input: true, + mask: false, + inputType: 'text', + inputFormat: 'plain', + spellcheck: true, + hideOnChildrenHidden: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, multiple: false, - defaultValue: null, - protected: false, unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'edz921k', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'e2ayb69', }, { - overlay: { - page: 1, - top: 999.2222222222222, - left: 387.4138888888889, - height: 22.095556130642336, - width: 389.90500508626303, - style: '', - }, - type: 'textfield', - key: 'lastName', - label: 'Last Name', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', + label: 'Form Url', + customDefaultValue: "value = instance.options?.embedFormSrc || '';", + key: 'src', + type: 'hidden', + input: true, + tableView: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, multiple: false, - defaultValue: null, - protected: false, unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e2de7sa', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + inputType: 'hidden', + id: 'ep1qgx', }, { - overlay: { - page: 1, - top: 998.6664444444444, - left: 81.85761111111108, - height: 23.24826724175342, - width: 299.9064457160102, - style: '', - }, - type: 'textfield', - key: 'firstName', - label: 'First Name', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', + label: 'Template', + widget: 'choicesjs', + tableView: true, + data: { + values: [ + { label: 'Boostrap 4', value: 'false' }, + { label: 'USWDS', value: 'uswds' }, + ], + json: '', + url: '', + resource: '', + custom: '', + }, + key: 'template', + type: 'select', + input: true, + hideOnChildrenHidden: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, multiple: false, - defaultValue: null, - protected: false, unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + onlyAvailableItems: false, + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + idPath: 'id', + clearOnRefresh: false, + limit: 100, + dataSrc: 'values', + valueProperty: '', + lazyLoad: true, + filter: '', + searchEnabled: true, + searchDebounce: 0.3, + searchField: '', + minSearch: 0, + readOnlyValue: false, + authenticate: false, + ignoreCache: false, + template: '{{ item.label }}', + selectFields: '', + selectThreshold: 0.3, + uniqueOptions: false, + fuseOptions: { include: 'score', threshold: 0.3 }, + indexeddb: { filter: {} }, + customOptions: {}, + useExactSearch: false, + id: 'ewk9iop', + }, + { + title: 'Advanced Settings', + collapsible: true, + key: 'advancedSettings', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ + { + label: 'Redirect', + tooltip: 'The URL you would like to redirect to after the form is submitted. ', + tableView: true, + key: 'redirect', + type: 'url', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, @@ -849,69 +3155,63 @@ export const w4 = { minLength: '', maxLength: '', pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'url', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'et7ayx', }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'eq3xm7d', - }, - { - overlay: { - page: 1, - top: 750.3336666666667, - left: 972.9684444444445, - height: '18', - width: '50', - style: '', - }, - type: 'textfield', - key: 'h', - label: 'H', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + { + label: 'Submission Endpoint', + tooltip: + 'The endpoint you would like to POST the submission toward. This allows you to send the submission to endpoints other than the default submission endpoint.', + tableView: true, + key: 'submit', + type: 'url', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, @@ -921,192 +3221,186 @@ export const w4 = { minLength: '', maxLength: '', pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'url', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'epa9s3i', }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'ej8thdm', - }, - { - input: true, - tableView: true, - label: 'G', - key: 'g', - type: 'textfield', - overlay: { width: '50', height: '18', left: 973.172, top: 726.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + { + label: 'Inherit Page CSS', + tooltip: + 'When it is unchecked, it loads all dependent CSS libraries to render the form.', + tableView: false, + defaultValue: false, + calculateValue: 'if (data.encapsulate) {\n value = true;\n}', + key: 'inherit', + type: 'checkbox', + input: true, + calculateValueMode: 'json', + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'right', + description: '', + errorLabel: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, strictDateValidation: false, multiple: false, unique: false, - minLength: '', - maxLength: '', - pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + inputType: 'checkbox', + value: '', + name: '', + id: 'e23lxjq', }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'esj0u5e', - }, - { - input: true, - tableView: true, - label: 'F', - key: 'f', - type: 'textfield', - overlay: { width: '50', height: '18', left: 973.172, top: 621.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + { + label: 'Debug Mode', + tooltip: + 'Add a number of console.log records to the browser on how this form is progressing through the embedding code.', + tableView: false, + defaultValue: false, + key: 'debug', + type: 'checkbox', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'right', + description: '', + errorLabel: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, strictDateValidation: false, multiple: false, unique: false, - minLength: '', - maxLength: '', - pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + inputType: 'checkbox', + value: '', + name: '', + id: 'eh4hyc', }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e0kdkzp', - }, - { - input: true, - tableView: true, - label: 'E', - key: 'e', - type: 'textfield', - overlay: { width: '50', height: '18', left: 973.172, top: 599.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + { + label: 'Custom Configurations', + description: + 'The following FormioConfig parameters can be specified: config, form, submission, libs.\n

Example:\n { "config": { "readOnly": true } }.\n
Click here for more examples.\n

\n', + tooltip: + 'Add configuration in JSON format for the global FormioConfig variable to control the embedded flow', + editor: 'ace', + autoExpand: false, + tableView: true, + key: 'config', + type: 'textarea', + as: 'json', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + errorLabel: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, @@ -1116,62 +3410,71 @@ export const w4 = { minLength: '', maxLength: '', pattern: '', + minWords: '', + maxWords: '', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'html', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + rows: 3, + wysiwyg: false, + fixedSize: true, + id: 'elmjv3ki', }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e4wp06', - }, - { - input: true, - tableView: true, - label: 'D', - key: 'd', - type: 'textfield', - overlay: { width: '50', height: '18', left: 972.672, top: 577.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + { + label: 'Before Render Handler', + description: + 'The callback accepts the following parameters: Formio, element, config. \n

Example:\nfunction(Formio, element, config) { console.log(Formio, element, config); }\n

', + tooltip: 'Provide a callback that is executed before the Form is rendered.', + editor: 'ace', + autoExpand: false, + tableView: true, + key: 'before', + type: 'textarea', + as: 'string', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + errorLabel: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, @@ -1181,62 +3484,71 @@ export const w4 = { minLength: '', maxLength: '', pattern: '', + minWords: '', + maxWords: '', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'html', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + rows: 3, + wysiwyg: false, + fixedSize: true, + id: 'ekd4ovh', }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'evg04s8', - }, - { - input: true, - tableView: true, - label: 'C', - key: 'c', - type: 'textfield', - overlay: { width: '50', height: '18', left: 972.672, top: 556.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + { + label: 'After Render Handler', + description: + 'The callback accepts instance variable as a parameter.\n

Example: function(instance) { console.log(instance); }\n

', + tooltip: 'Provide a callback that is called after the form is done rendering.', + editor: 'ace', + autoExpand: false, + tableView: true, + key: 'after', + type: 'textarea', + as: 'string', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + errorLabel: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, @@ -1246,4740 +3558,2362 @@ export const w4 = { minLength: '', maxLength: '', pattern: '', + minWords: '', + maxWords: '', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'html', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + rows: 3, + wysiwyg: false, + fixedSize: true, + id: 'eiqb29', }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e953emh', - }, - { - input: true, - tableView: true, - label: 'B', - key: 'b', - type: 'textfield', - overlay: { width: '50', height: '18', left: 972.672, top: 493, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', + ], + collapsed: true, + hideOnChildrenHidden: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: false, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, multiple: false, - defaultValue: null, - protected: false, unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e2l0zzm', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + tree: false, + lazyLoad: false, + theme: 'default', + breadcrumb: 'default', + id: 'e71fwgr', }, + ], + hideOnChildrenHidden: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: false, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + tree: false, + lazyLoad: false, + theme: 'default', + breadcrumb: 'default', + id: 'e8be5t4', + }, + ], + revisions: 'current', + _vid: 4, + title: 'Inline Embed Form - Portal', + display: 'form', + access: [ + { + roles: ['5692b920d1028f01000407e4', '5692b920d1028f01000407e5', '5692b920d1028f01000407e6'], + type: 'read_all', + }, + ], + submissionAccess: [], + controller: '', + properties: {}, + settings: {}, + name: 'inlineEmbedFormPortal', + path: 'inlineembedformportal', + project: '5692b91fd1028f01000407e3', + created: '2021-10-29T14:20:28.581Z', + modified: '2022-11-17T15:09:31.641Z', + machineName: 'examples:inlineEmbedFormPortal', +}; + +export const validationRulesNyHealth = { + _id: '617051c6a8135f6a0780c364', + type: 'form', + tags: [], + owner: '5d921ec842af9789e5b81b26', + components: [ + { + title: 'Case 1', + collapsible: false, + key: 'case1', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - input: true, - tableView: true, - label: 'A', - key: 'a', - type: 'textfield', - overlay: { width: '50', height: '18', left: 972.469, top: 449.375, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'egw3xvl', + label: 'HTML', + attrs: [{ attr: '', value: '' }], + content: + '

Case 1:

\n

Box a value can not differ by a factor(.5) of n from Box b

\n• EX: 100(b) -> a(max)50', + refreshOnChange: false, + key: 'html1', + type: 'htmlelement', + input: false, + tableView: false, }, { - input: true, - label: 'Submit', - tableView: false, - key: 'submit', - type: 'button', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - size: 'md', - leftIcon: '', - rightIcon: '', - block: false, - action: 'submit', - disableOnInvalid: false, - theme: 'primary', - id: 'etn79o', + label: 'Box a', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + validate: { + customMessage: 'Needs to be within the range. ', + custom: 'valid = input >= (data.boxB * 0.5) && input <= (data.boxB * 1.5);', + }, + errorLabel: 'Box A Value', + key: 'boxA', + type: 'number', + input: true, }, - ], - owner: '553dbfc08d22d5cb1a7024f2', - submissionAccess: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', + label: 'Box b', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + key: 'boxB', + type: 'number', + input: true, }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - tags: [], - type: 'form', - _vid: 0, - revisions: '', -}; - -export const example = { - _id: '57aa1d2a5b7a477b002717fe', - machineName: 'examples:example', - modified: '2022-12-09T17:14:46.932Z', - title: 'Example', - display: 'form', - type: 'form', - name: 'example', - path: 'example', - project: '5692b91fd1028f01000407e3', - created: '2016-08-09T18:12:58.126Z', - components: [ + ], + }, + { + title: 'Case 2 / Case 3', + collapsible: false, + key: 'case2', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - input: false, - html: '

Form.io Example Form

\n\n

This is a dynamically rendered JSON form built with Form.io. Using a simple drag-and-drop form builder, you can create any form that includes e-signatures, wysiwyg editors, date fields, layout components, data grids, surveys, etc.

\n', - type: 'content', - conditional: { show: '', when: null, eq: '' }, - key: 'content', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - tableView: false, - modalEdit: false, - label: 'Content', - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - id: 'e4w5wnn', - addons: [], + label: 'HTML', + attrs: [{ attr: '', value: '' }], + content: + '

Case 2:

\n

Box b must compare the value on the number of repeating section

\n• Value of b must match the amount of repeating section
\n• Number of repeating sections must not exceed value of b\n\n

Case 3:

\n

Box b in a repeating section 1a must be unique in all repeating section

', + refreshOnChange: false, + key: 'html', + type: 'htmlelement', + input: false, + tableView: false, }, { - input: false, - columns: [ - { - components: [ - { - tabindex: '1', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - inputType: 'text', - inputMask: '', - label: 'First Name', - key: 'firstName', - placeholder: 'Enter your first name', - prefix: '', - suffix: '', - multiple: false, - defaultValue: '', - protected: false, - unique: false, - persistent: true, - validate: { - required: false, - minLength: '', - maxLength: '', - pattern: '', - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: '', when: null, eq: '' }, - type: 'textfield', - customClass: '', - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputFormat: 'plain', - spellcheck: true, - id: 'ek1pl3', - addons: [], - displayMask: '', - truncateMultipleSpaces: false, - }, - { - tabindex: '3', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - inputType: 'email', - label: 'Email', - key: 'email', - placeholder: 'Enter your email address', - prefix: '', - suffix: '', - defaultValue: '', - protected: false, - unique: false, - persistent: true, - type: 'email', - conditional: { show: '', when: null, eq: '' }, - kickbox: { enabled: false }, - customClass: '', - multiple: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputFormat: 'plain', - inputMask: '', - spellcheck: true, - id: 'en2328', - addons: [], - displayMask: '', - truncateMultipleSpaces: false, - }, - ], - width: 6, - offset: 0, - push: 0, - pull: 0, - size: 'md', - currentWidth: 6, - }, - { - components: [ - { - tabindex: '2', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - inputType: 'text', - inputMask: '', - label: 'Last Name', - key: 'lastName', - placeholder: 'Enter your last name', - prefix: '', - suffix: '', - multiple: false, - defaultValue: '', - protected: false, - unique: false, - persistent: true, - validate: { - required: false, - minLength: '', - maxLength: '', - pattern: '', - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: '', when: null, eq: '' }, - type: 'textfield', - customClass: '', - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputFormat: 'plain', - spellcheck: true, - id: 'ex6xzd', - addons: [], - displayMask: '', - truncateMultipleSpaces: false, - }, - { - tabindex: '4', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - inputMask: '(999) 999-9999', - label: 'Phone Number', - key: 'phoneNumber', - placeholder: 'Enter your phone number', - prefix: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - defaultValue: '', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - type: 'phoneNumber', - conditional: { show: '', when: null, eq: '' }, - customClass: '', - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: 'tel', - inputFormat: 'plain', - spellcheck: true, - inputMode: 'decimal', - id: 'ecee6s', - addons: [], - displayMask: '', - truncateMultipleSpaces: false, - }, - ], - width: 6, - offset: 0, - push: 0, - pull: 0, - size: 'md', - currentWidth: 6, - }, - ], - type: 'columns', - conditional: { show: '', when: null, eq: '' }, - key: 'columns', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: false, - refreshOn: '', - redrawOn: '', - tableView: false, - modalEdit: false, - label: 'Columns', - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - tree: false, - autoAdjust: false, - id: 'e2i9r0c', - addons: [], - lazyLoad: false, + label: 'Box b', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + calculateValue: + "var dataGrid = instance.root.getComponent('dataGrid');\ndataGrid.component.validate.minLength = parseInt(value, 10);\ndataGrid.component.validate.maxLength = parseInt(value, 10);\ninstance.root.redraw();", + key: 'boxB1', + type: 'number', + input: true, }, { - tabindex: '5', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - label: 'Survey', - key: 'survey', - questions: [ - { - value: 'howWouldYouRateTheFormIoPlatform', - label: 'How would you rate the Form.io platform?', - }, - { value: 'howWasCustomerSupport', label: 'How was Customer Support?' }, - { value: 'overallExperience', label: 'Overall Experience?' }, - ], - values: [ - { value: 'excellent', label: 'Excellent' }, - { value: 'great', label: 'Great' }, - { value: 'good', label: 'Good' }, - { value: 'average', label: 'Average' }, - { value: 'poor', label: 'Poor' }, - ], - defaultValue: '', - protected: false, - persistent: true, - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + label: 'Data Grid', + reorder: false, + addAnotherPosition: 'bottom', + layoutFixed: false, + enableRowGroups: false, + initEmpty: false, + tableView: false, + defaultValue: [{ uniqueName: '' }], + key: 'dataGrid', + type: 'datagrid', + input: true, + components: [ + { + label: 'Unique Name', + tableView: true, + unique: true, + key: 'uniqueName', + type: 'textfield', + input: true, }, - type: 'survey', - conditional: { show: '', when: null, eq: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - unique: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - id: 'ek3vrnp', - addons: [], + ], }, + ], + breadcrumbClickable: true, + buttonSettings: { previous: true, cancel: true, next: true }, + scrollToTop: false, + }, + { + title: 'Case 4', + collapsible: false, + key: 'case7', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - label: 'Signature', - key: 'signature', - placeholder: '', - footer: 'Sign above', - width: '100%', - height: '150px', - penColor: 'black', - backgroundColor: 'rgb(245,245,235)', - minWidth: '0.5', - maxWidth: '2.5', - protected: false, - persistent: true, - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - type: 'signature', - hideLabel: true, - conditional: { show: '', when: null, eq: '' }, - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - unique: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - id: 'e4zac8j', - addons: [], - keepOverlayRatio: true, + label: 'HTML', + attrs: [{ attr: '', value: '' }], + content: + '

Case 4:

\n

Box b in a repeating section a1 must be greater then Box b in repeating section a2.

', + refreshOnChange: false, + key: 'html2', + type: 'htmlelement', + input: false, + tableView: false, }, { - tabindex: '6', - conditional: { eq: '', when: null, show: '' }, - tags: [], - input: true, - label: 'Submit', - tableView: false, - key: 'submit', - size: 'md', - leftIcon: '', - rightIcon: '', - block: false, - action: 'submit', - disableOnInvalid: true, - theme: 'primary', - type: 'button', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + title: 'Case 4.1', + collapsible: false, + key: 'case4', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ + { + label: 'Number1', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + key: 'number1', + type: 'number', + input: true, }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - id: 'et5j8rn', - addons: [], - }, - ], - owner: '554806425867f4ee203ea861', - submissionAccess: [ - { roles: ['5692b920d1028f01000407e6'], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - '000000000000000000000000', - ], - type: 'read_all', + ], }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - tags: [], - _vid: 0, - revisions: '', -}; - -export const simpleForm = { - _id: '641b2ba3488ffcafa27c2e9f', - title: 'Simple Form', - name: 'simpleForm', - path: 'simpleform', - type: 'form', - display: 'form', - tags: [], - components: [ { - label: 'Required Field', - applyMaskOn: 'change', - tableView: true, - validate: { - required: true, + title: 'Case 4.2', + collapsible: false, + key: 'case42', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ + { + label: 'Number2', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + validate: { + customMessage: 'Value must be greater than or equal to Number1', + custom: 'valid = input>=data.number1;', + }, + key: 'number2', + type: 'number', + input: true, }, - key: 'requiredField', - type: 'textfield', - input: true, + ], }, + ], + }, + { + title: 'Case 5', + collapsible: false, + key: 'case5', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - label: 'Maximum Words', - applyMaskOn: 'change', - autoExpand: false, - tableView: true, - validate: { - maxWords: 4, - }, - key: 'maximumWords', - type: 'textarea', - input: true, + label: 'HTML', + attrs: [{ attr: '', value: '' }], + content: + '

Case 5:

\n

Box b in a repeating section a1 must be greater than Box c in repeating section a1. and also it can be applied to fields outside repeating section

\n', + refreshOnChange: false, + key: 'html3', + type: 'htmlelement', + input: false, + tableView: false, }, { - label: 'Minimum Words', - applyMaskOn: 'change', - autoExpand: false, - tableView: true, - validate: { - minWords: 2, + label: 'Data Grid', + reorder: false, + addAnotherPosition: 'bottom', + layoutFixed: false, + enableRowGroups: false, + initEmpty: false, + tableView: false, + defaultValue: [{}], + key: 'dataGrid1', + type: 'datagrid', + input: true, + components: [ + { + label: 'Number3', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + key: 'number3', + type: 'number', + input: true, }, - key: 'minimumWords', - type: 'textarea', - input: true, + { + label: 'Number4', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + validate: { + customMessage: 'must be greater than the value in Number3', + custom: 'valid = input>row.number3;\n', + }, + errorLabel: 'Number4', + key: 'number4', + type: 'number', + input: true, + }, + ], }, { - label: 'Email', - applyMaskOn: 'change', - tableView: true, - key: 'email', - type: 'email', - input: true, + title: 'Case 5 - Number outside of Section', + tooltip: + 'This is dependent on which value in the repeating section above would need to be validated against.', + collapsible: false, + key: 'case5NumberOutsideOfSection1', + type: 'panel', + label: 'Case 5 - Number outside of Section', + input: false, + tableView: false, + components: [ + { + label: 'Number5', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + validate: { + customMessage: 'Value must be greater than Number3', + custom: 'valid = input>data.number3;', + }, + key: 'number6', + type: 'number', + input: true, + }, + ], }, + ], + }, + { + title: 'Case 6 - Min / Max Date from Today', + collapsible: false, + key: 'case6', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - label: 'Url', - applyMaskOn: 'change', - tableView: true, - key: 'url', - type: 'url', - input: true, + label: 'HTML', + attrs: [{ attr: '', value: '' }], + content: + '

Case 6:

\n

Date field d should have a date that is at most/least N days/weeks/months/years ago/ from today\n \n

', + refreshOnChange: false, + key: 'html4', + type: 'htmlelement', + input: false, + tableView: false, }, { - label: 'Input Mask', - applyMaskOn: 'change', - tableView: true, - key: 'inputMask', - type: 'phoneNumber', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { - type: 'input', - }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { - show: null, - when: null, - eq: '', - }, - overlay: { - style: '', - left: '', - top: '', - width: '', - height: '', - }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'tel', - inputFormat: 'plain', - inputMask: '(999) 999-9999', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - inputMode: 'decimal', - id: 'e8vls3a', - keyModified: true, - }, - { - label: 'Time', - type: 'time', - key: 'time', - input: true, - dataFormat: 'HH:mm:ss', - format: 'HH:mm', - multiple: true, + label: 'Date / Time', + tableView: false, + enableMinDateInput: true, + datePicker: { + disableWeekends: false, + disableWeekdays: false, + maxDate: "moment().add(10, 'days')", + minDate: "moment().subtract(10, 'days')", + }, + enableMaxDateInput: true, + key: 'dateTime', + type: 'datetime', + input: true, + widget: { + type: 'calendar', + displayInTimezone: 'viewer', + locale: 'en', + useLocaleSettings: false, + allowInput: true, + mode: 'single', + enableTime: true, + noCalendar: false, + format: 'yyyy-MM-dd hh:mm a', + hourIncrement: 1, + minuteIncrement: 1, + time_24hr: false, + minDate: "moment().subtract(10, 'days')", + disableWeekends: false, + disableWeekdays: false, + maxDate: "moment().add(10, 'days')", + }, }, - { - type: 'button', - label: 'Submit', - key: 'submit', - disableOnInvalid: true, - input: true, - tableView: false, - } - ], - settings: {}, - properties: {}, - project: '6419d8f2322509215938a9e6', - controller: '', - revisions: '', - submissionRevisions: '', - _vid: 0, - created: '2023-03-22T16:24:03.220Z', - modified: '2023-03-22T16:27:12.193Z', - machineName: 'qgvzeueerscrxbs:simpleForm', + ], + }, + { + type: 'button', + label: 'Submit', + key: 'submit', + disableOnInvalid: true, + input: true, + tableView: false, + }, + ], + revisions: '', + _vid: 0, + title: 'Validation Rules - NY Health', + display: 'wizard', + access: [ + { + roles: ['5692b920d1028f01000407e4', '5692b920d1028f01000407e5', '5692b920d1028f01000407e6'], + type: 'read_all', + }, + ], + submissionAccess: [], + controller: '', + properties: {}, + settings: {}, + name: 'validationRulesNyHealth', + path: 'validationrulesnyhealth', + project: '5692b91fd1028f01000407e3', + created: '2021-10-20T17:28:38.165Z', + modified: '2021-10-20T18:08:13.287Z', + machineName: 'examples:validationRulesNyHealth', }; -export const wizard = { - _id: '578f930ef1912f8000459a50', - machineName: 'examples:wizard', - modified: '2022-11-17T20:30:28.519Z', - title: 'Wizard', - display: 'wizard', - type: 'form', - name: 'wizard', - path: 'wizard', - project: '5692b91fd1028f01000407e3', - created: '2016-07-20T15:04:46.906Z', - components: [ - { - key: 'page1', - input: false, - components: [ - { - type: 'textfield', - multiple: true, - key: 'textfieldonpage1', - label: 'Textfield on page 1', - tableView: true, - input: true, - }, - { - type: 'number', - validate: { required: true }, - defaultValue: 0, - key: 'numberField', - label: 'Number Field', - inputType: 'number', - tableView: true, - input: true, - }, - ], - title: 'First', - type: 'panel', - tableView: false, - label: 'Panel', - }, +export const inlineembed = { + _id: '60089c6795f584688609f83c', + type: 'form', + tags: [], + owner: '553dbfc08d22d5cb1a7024f2', + components: [ + { + html: '

This is a form that enables the configuration of a Quick Inline Embed for a Form.io form.

For advanced documentation on how to use this embedding feature, please see our Quick Inline Embed Documentation.

', + label: 'Content', + refreshOnChange: false, + key: 'content', + type: 'content', + input: false, + tableView: false, + }, + { + label: 'Columns', + columns: [ { - tableView: false, - key: 'page2', - input: false, - components: [ + components: [ + { + title: 'Embed Configuration', + collapsible: false, + key: 'embedConfiguration', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - type: 'textfield', - validate: { required: true }, - key: 'textfieldonPage2', - label: 'Textfield on Page 2', - tableView: true, - input: true, + label: 'Embed Script', + defaultValue: 'https://cdn.form.io/formiojs/formio.embed.js', + key: 'embed', + type: 'hidden', + tableView: true, + input: true, + mask: false, + inputType: 'text', + inputFormat: 'plain', + spellcheck: true, + hideOnChildrenHidden: false, }, { - input: true, - tableView: true, - label: 'Customer', - key: 'page2Customer', - placeholder: 'Select a customer', - data: { - url: 'https://examples.form.io/customer/submission', - headers: [{ value: '', key: '' }], - }, - dataSrc: 'url', - valueProperty: 'data.email', - template: '{{ item.data.firstName }} {{ item.data.lastName }}', - type: 'select', - widget: 'html5', - searchField: 'data.email', + label: 'Project', + tableView: true, + key: 'project', + type: 'hidden', + input: true, + mask: false, + inputType: 'text', + inputFormat: 'plain', + spellcheck: true, + hideOnChildrenHidden: false, }, { - clearOnHide: false, - type: 'fieldset', - components: [ - { - type: 'textfield', - key: 'textfield', - label: 'Textfield', - tableView: true, - input: true, - }, - ], - legend: 'FieldSet Label', - tableView: true, - input: false, - key: 'fieldSet', - label: 'Field Set', + label: 'Base', + tableView: true, + key: 'base', + type: 'hidden', + input: true, + mask: false, + inputType: 'text', + inputFormat: 'plain', + spellcheck: true, + hideOnChildrenHidden: false, }, - ], - title: 'Page 2', - type: 'panel', - label: 'Panel', - }, - { - type: 'panel', - components: [ { - input: true, - tableView: true, - label: 'Text', - key: 'panelText', - validate: { required: true }, - type: 'textfield', + label: 'Form URL', + tableView: true, + validate: { required: true }, + key: 'src', + type: 'textfield', + input: true, + defaultValue: 'https://examples.form.io/example', + hideOnChildrenHidden: false, }, { - type: 'datagrid', - key: 'panelDataGrid', - label: 'Data Grid', - tableView: true, - components: [ - { - hideLabel: true, - type: 'textfield', - key: 'panelDataGridA', - label: 'A', - tableView: true, - input: true, - inDataGrid: true, - }, - { - hideLabel: true, - type: 'textfield', - key: 'panelDataGridB', - label: 'B', - tableView: true, - input: true, - inDataGrid: true, - }, - { - hideLabel: true, - type: 'textfield', - key: 'panelDataGridC', - label: 'C', - tableView: true, - input: true, - inDataGrid: true, - }, - { - hideLabel: true, - type: 'textfield', - key: 'panelDataGridD', - label: 'D', - tableView: true, - input: true, - inDataGrid: true, - }, + label: 'Template', + widget: 'choicesjs', + tableView: true, + data: { + values: [ + { label: 'Boostrap 4', value: 'false' }, + { label: 'USWDS', value: 'uswds' }, ], - input: true, - }, - { - input: true, - tableView: true, - label: 'HTML5 Select', - key: 'panelHtml5Select', - data: { - values: [ - { value: 'orange', label: 'Orange' }, - { value: 'apple', label: 'Apple' }, - { value: 'banana', label: 'Banana' }, - { value: 'strawberry', label: 'Strawberry' }, - { value: 'kiwi', label: 'Kiwi' }, - ], - }, - widget: 'html5', - type: 'select', - }, - ], - tableView: false, - title: 'Page 3', - input: false, - key: 'panel', - label: 'Panel', - }, - { - key: 'page3', - input: false, - components: [ - { - type: 'textfield', - key: 'textfieldonPage3', - label: 'Textfield on Page 3', - tableView: true, - input: true, - }, - { - input: true, - tableView: true, - label: 'I agree to the follow the rules', - dataGridLabel: false, - key: 'page3Iagreetothefollowtherules', - defaultValue: false, - type: 'checkbox', + }, + key: 'template', + type: 'select', + input: true, + searchThreshold: 0.3, + hideOnChildrenHidden: false, }, { - input: true, - tableView: true, - label: 'Signature', - key: 'signature', - type: 'signature', - hideLabel: true, - lockKey: true, - }, - ], - title: 'Last', - type: 'panel', - tableView: false, - label: 'Panel', - }, - { - type: 'button', - disableOnInvalid: true, - key: 'submit', - tableView: false, - label: 'Submit', - input: true, - }, - ], - owner: '55673dc04f0405dd28205bb7', - submissionAccess: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: ['5692b920d1028f01000407e6'], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', - }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - tags: ['common'], - settings: { - controller: - "['$scope', function($scope) { $scope.$watch('submission.data', function(data) { console.log(data); }, true); }]", - }, - revisions: '', - _vid: 0, - controller: '', - properties: {}, -}; - -export const inlineEmbedFormPortal = { - _id: '617c032c68daf082ce063303', - type: 'form', - tags: [], - owner: '5e4aa9cf4037892ed27d5550', - components: [ - { - label: 'HTML', - tag: 'div', - attrs: [{ attr: '', value: '' }], - content: - "

Quick Inline Embed

\r\n

To quickly embed this form without using any framework, you can use the following code snippit and configure it using the Inline Embed Configuration form below.

\r\n

See our Inline Embed Documentation to know more about it.

", - refreshOnChange: false, - key: 'html1', - type: 'htmlelement', - input: false, - tableView: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'emraund', - }, - { - label: 'HTML', - tag: 'pre', - attrs: [{ attr: '', value: '' }], - content: - '', - refreshOnChange: true, - key: 'html', - type: 'htmlelement', - input: false, - tableView: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'e3wopjp', - }, - { - label: 'Copy to Clipboard', - action: 'custom', - showValidations: false, - theme: 'success', - block: true, - leftIcon: 'fa fa-copy', - tableView: false, - key: 'copyToClipboard', - type: 'button', - custom: 'var embedCode = document.getElementById(\'embed-code\');\nif (embedCode) {\n embedCode.focus();\n embedCode.select();\n document.execCommand("copy");\n}', - input: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - size: 'md', - rightIcon: '', - disableOnInvalid: false, - id: 'eq2y2ul', - }, - { - title: 'Inline Embed Configuration', - collapsible: false, - key: 'embedConfiguration', - type: 'panel', - label: 'Inline Embed Configuration', - input: false, - tableView: false, - components: [ - { - label: 'Embed Script', - customDefaultValue: "value = instance.options?.quickInlineEmbed || '';", - key: 'embed', - type: 'hidden', - tableView: true, - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + title: 'Advanced Settings', + collapsible: true, + key: 'advancedSettings', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ + { + label: 'Redirect', + tableView: true, + key: 'redirect', + type: 'url', + input: true, }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'eq04647', - }, - { - label: 'Project', - tableView: true, - key: 'project', - type: 'hidden', - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + { + label: 'Submission Endpoint', + tableView: true, + key: 'submit', + type: 'url', + input: true, }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'eowdp4', - }, - { - label: 'Base', - tableView: true, - key: 'base', - type: 'hidden', - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + { + label: 'Inherit Page CSS', + tableView: false, + defaultValue: true, + calculateValue: 'if (data.encapsulate) {\n value = true;\n}', + key: 'inherit', + type: 'checkbox', + input: true, }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'e2ayb69', - }, - { - label: 'Form Url', - customDefaultValue: "value = instance.options?.embedFormSrc || '';", - key: 'src', - type: 'hidden', - input: true, - tableView: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + { + label: 'Debug Mode', + tableView: false, + key: 'debug', + type: 'checkbox', + input: true, + defaultValue: false, }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - inputType: 'hidden', - id: 'ep1qgx', - }, - { - label: 'Template', - widget: 'choicesjs', - tableView: true, - data: { - values: [ - { label: 'Boostrap 4', value: 'false' }, - { label: 'USWDS', value: 'uswds' }, - ], - json: '', - url: '', - resource: '', - custom: '', + { + label: 'Custom Configurations', + editor: 'ace', + autoExpand: false, + tableView: true, + key: 'config', + type: 'textarea', + as: 'json', + input: true, }, - key: 'template', - type: 'select', - input: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - onlyAvailableItems: false, + { + input: true, + key: 'before', + tableView: true, + label: 'Before Render Handler', + type: 'textarea', + editor: 'ace', + as: 'string', }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - idPath: 'id', - clearOnRefresh: false, - limit: 100, - dataSrc: 'values', - valueProperty: '', - lazyLoad: true, - filter: '', - searchEnabled: true, - searchDebounce: 0.3, - searchField: '', - minSearch: 0, - readOnlyValue: false, - authenticate: false, - ignoreCache: false, - template: '{{ item.label }}', - selectFields: '', - selectThreshold: 0.3, - uniqueOptions: false, - fuseOptions: { include: 'score', threshold: 0.3 }, - indexeddb: { filter: {} }, - customOptions: {}, - useExactSearch: false, - id: 'ewk9iop', - }, - { - title: 'Advanced Settings', - collapsible: true, - key: 'advancedSettings', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Redirect', - tooltip: - 'The URL you would like to redirect to after the form is submitted. ', - tableView: true, - key: 'redirect', - type: 'url', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'url', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'et7ayx', - }, - { - label: 'Submission Endpoint', - tooltip: - 'The endpoint you would like to POST the submission toward. This allows you to send the submission to endpoints other than the default submission endpoint.', - tableView: true, - key: 'submit', - type: 'url', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'url', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'epa9s3i', - }, - { - label: 'Inherit Page CSS', - tooltip: - 'When it is unchecked, it loads all dependent CSS libraries to render the form.', - tableView: false, - defaultValue: false, - calculateValue: 'if (data.encapsulate) {\n value = true;\n}', - key: 'inherit', - type: 'checkbox', - input: true, - calculateValueMode: 'json', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - inputType: 'checkbox', - value: '', - name: '', - id: 'e23lxjq', - }, - { - label: 'Debug Mode', - tooltip: - 'Add a number of console.log records to the browser on how this form is progressing through the embedding code.', - tableView: false, - defaultValue: false, - key: 'debug', - type: 'checkbox', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - inputType: 'checkbox', - value: '', - name: '', - id: 'eh4hyc', - }, - { - label: 'Custom Configurations', - description: - 'The following FormioConfig parameters can be specified: config, form, submission, libs.\n

Example:\n { "config": { "readOnly": true } }.\n
Click here for more examples.\n

\n', - tooltip: - 'Add configuration in JSON format for the global FormioConfig variable to control the embedded flow', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'config', - type: 'textarea', - as: 'json', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - minWords: '', - maxWords: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'html', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - rows: 3, - wysiwyg: false, - fixedSize: true, - id: 'elmjv3ki', - }, - { - label: 'Before Render Handler', - description: - 'The callback accepts the following parameters: Formio, element, config. \n

Example:\nfunction(Formio, element, config) { console.log(Formio, element, config); }\n

', - tooltip: - 'Provide a callback that is executed before the Form is rendered.', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'before', - type: 'textarea', - as: 'string', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - minWords: '', - maxWords: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'html', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - rows: 3, - wysiwyg: false, - fixedSize: true, - id: 'ekd4ovh', - }, - { - label: 'After Render Handler', - description: - 'The callback accepts instance variable as a parameter.\n

Example: function(instance) { console.log(instance); }\n

', - tooltip: - 'Provide a callback that is called after the form is done rendering.', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'after', - type: 'textarea', - as: 'string', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - minWords: '', - maxWords: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'html', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - rows: 3, - wysiwyg: false, - fixedSize: true, - id: 'eiqb29', - }, - ], - collapsed: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + { + label: 'After Render Handler', + editor: 'ace', + autoExpand: false, + tableView: true, + key: 'after', + type: 'textarea', + as: 'string', + input: true, }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - tree: false, - lazyLoad: false, - theme: 'default', - breadcrumb: 'default', - id: 'e71fwgr', + ], + collapsed: true, + hideOnChildrenHidden: false, }, - ], - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + ], + hideOnChildrenHidden: false, }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - tree: false, - lazyLoad: false, - theme: 'default', - breadcrumb: 'default', - id: 'e8be5t4', - }, - ], - revisions: 'current', - _vid: 4, - title: 'Inline Embed Form - Portal', - display: 'form', - access: [ - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', - }, - ], - submissionAccess: [], - controller: '', - properties: {}, - settings: {}, - name: 'inlineEmbedFormPortal', - path: 'inlineembedformportal', - project: '5692b91fd1028f01000407e3', - created: '2021-10-29T14:20:28.581Z', - modified: '2022-11-17T15:09:31.641Z', - machineName: 'examples:inlineEmbedFormPortal', -}; - -export const validationRulesNyHealth = { - _id: '617051c6a8135f6a0780c364', - type: 'form', - tags: [], - owner: '5d921ec842af9789e5b81b26', - components: [ - { - title: 'Case 1', - collapsible: false, - key: 'case1', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 1:

\n

Box a value can not differ by a factor(.5) of n from Box b

\n• EX: 100(b) -> a(max)50', - refreshOnChange: false, - key: 'html1', - type: 'htmlelement', - input: false, - tableView: false, - }, - { - label: 'Box a', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - validate: { - customMessage: 'Needs to be within the range. ', - custom: 'valid = input >= (data.boxB * 0.5) && input <= (data.boxB * 1.5);', - }, - errorLabel: 'Box A Value', - key: 'boxA', - type: 'number', - input: true, - }, - { - label: 'Box b', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - key: 'boxB', - type: 'number', - input: true, - }, - ], - }, - { - title: 'Case 2 / Case 3', - collapsible: false, - key: 'case2', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 2:

\n

Box b must compare the value on the number of repeating section

\n• Value of b must match the amount of repeating section
\n• Number of repeating sections must not exceed value of b\n\n

Case 3:

\n

Box b in a repeating section 1a must be unique in all repeating section

', - refreshOnChange: false, - key: 'html', - type: 'htmlelement', - input: false, - tableView: false, - }, - { - label: 'Box b', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - calculateValue: - "var dataGrid = instance.root.getComponent('dataGrid');\ndataGrid.component.validate.minLength = parseInt(value, 10);\ndataGrid.component.validate.maxLength = parseInt(value, 10);\ninstance.root.redraw();", - key: 'boxB1', - type: 'number', - input: true, - }, - { - label: 'Data Grid', - reorder: false, - addAnotherPosition: 'bottom', - layoutFixed: false, - enableRowGroups: false, - initEmpty: false, - tableView: false, - defaultValue: [{ uniqueName: '' }], - key: 'dataGrid', - type: 'datagrid', - input: true, - components: [ - { - label: 'Unique Name', - tableView: true, - unique: true, - key: 'uniqueName', - type: 'textfield', - input: true, - }, - ], - }, - ], - breadcrumbClickable: true, - buttonSettings: { previous: true, cancel: true, next: true }, - scrollToTop: false, + ], + width: 6, + offset: 0, + push: 0, + pull: 0, + size: 'md', + currentWidth: 6, }, { - title: 'Case 4', - collapsible: false, - key: 'case7', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ + components: [ + { + title: 'Embed Code', + collapsible: false, + key: 'embedCode', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 4:

\n

Box b in a repeating section a1 must be greater then Box b in repeating section a2.

', - refreshOnChange: false, - key: 'html2', - type: 'htmlelement', - input: false, - tableView: false, + label: 'HTML', + tag: 'pre', + attrs: [{ attr: '', value: '' }], + content: + '', + refreshOnChange: true, + key: 'html', + type: 'htmlelement', + input: false, + tableView: false, }, { - title: 'Case 4.1', - collapsible: false, - key: 'case4', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Number1', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - key: 'number1', - type: 'number', - input: true, - }, - ], + label: 'Copy to Clipboard', + action: 'custom', + showValidations: false, + theme: 'success', + block: true, + leftIcon: 'fa fa-copy', + tableView: false, + key: 'copyToClipboard', + type: 'button', + custom: + 'var embedCode = document.getElementById(\'embed-code\');\nif (embedCode) {\n embedCode.focus();\n embedCode.select();\n document.execCommand("copy");\n}', + input: true, + hideOnChildrenHidden: false, }, - { - title: 'Case 4.2', - collapsible: false, - key: 'case42', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Number2', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - validate: { - customMessage: 'Value must be greater than or equal to Number1', - custom: 'valid = input>=data.number1;', - }, - key: 'number2', - type: 'number', - input: true, - }, - ], - }, - ], + ], + hideOnChildrenHidden: false, + }, + ], + width: 6, + offset: 0, + push: 0, + pull: 0, + size: 'md', + currentWidth: 6, }, + ], + hideOnChildrenHidden: false, + key: 'columns', + type: 'columns', + input: false, + tableView: false, + }, + ], + revisions: '', + _vid: 0, + title: 'Quick Inline Embed', + display: 'form', + access: [ + { + roles: ['5692b920d1028f01000407e4', '5692b920d1028f01000407e5', '5692b920d1028f01000407e6'], + type: 'read_all', + }, + ], + submissionAccess: [], + controller: '', + properties: {}, + settings: {}, + name: 'inlineembed', + path: 'embed', + project: '5692b91fd1028f01000407e3', + created: '2021-01-20T21:11:03.957Z', + modified: '2021-10-18T16:34:28.512Z', + machineName: 'examples:inlineEmbedConfiguration', +}; + +export const customerLoad = { + _id: '5aa316c59f3918304b469e82', + title: 'Customer Load', + display: 'form', + type: 'form', + components: [ + { + input: true, + tableView: true, + inputType: 'number', + label: 'Customer Number', + key: 'customerNumber', + validate: { required: true, min: 1, max: 9 }, + type: 'number', + }, + { input: true, tableView: true, label: 'Name', key: 'name', type: 'textfield' }, + { + input: true, + tableView: true, + label: 'Phone Number', + key: 'phoneNumber', + type: 'textfield', + }, + { input: true, label: 'Submit', tableView: false, key: 'submit', type: 'button' }, + ], + access: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { + roles: [ + '5692b920d1028f01000407e4', + '5692b920d1028f01000407e5', + '5692b920d1028f01000407e6', + '000000000000000000000000', + ], + type: 'read_all', + }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + submissionAccess: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { roles: [], type: 'read_all' }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + settings: {}, + name: 'customerLoad', + path: 'customerload', + owner: '55673dc04f0405dd28205bb7', + project: '5692b91fd1028f01000407e3', + tags: [], + created: '2018-03-09T23:20:37.966Z', + revisions: '', + _vid: 0, + modified: '2021-09-15T17:09:44.770Z', + machineName: 'examples:customerLoad', +}; + +export const kitchenSink = { + _id: '5d7a42f21cc1c2ca88ff2dd5', + type: 'form', + tags: [], + owner: '553dbfc08d22d5cb1a7024f2', + components: [ + { + label: 'Panel', + title: 'User Information', + collapsible: false, + mask: false, + tableView: false, + alwaysEnabled: false, + type: 'panel', + input: false, + key: 'panel2', + components: [ { - title: 'Case 5', - collapsible: false, - key: 'case5', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 5:

\n

Box b in a repeating section a1 must be greater than Box c in repeating section a1. and also it can be applied to fields outside repeating section

\n', - refreshOnChange: false, - key: 'html3', - type: 'htmlelement', - input: false, - tableView: false, - }, + label: 'Columns', + columns: [ + { + components: [ { - label: 'Data Grid', - reorder: false, - addAnotherPosition: 'bottom', - layoutFixed: false, - enableRowGroups: false, - initEmpty: false, - tableView: false, - defaultValue: [{}], - key: 'dataGrid1', - type: 'datagrid', - input: true, - components: [ - { - label: 'Number3', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - key: 'number3', - type: 'number', - input: true, - }, - { - label: 'Number4', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - validate: { - customMessage: 'must be greater than the value in Number3', - custom: 'valid = input>row.number3;\n', - }, - errorLabel: 'Number4', - key: 'number4', - type: 'number', - input: true, - }, - ], - }, - { - title: 'Case 5 - Number outside of Section', - tooltip: - 'This is dependent on which value in the repeating section above would need to be validated against.', - collapsible: false, - key: 'case5NumberOutsideOfSection1', - type: 'panel', - label: 'Case 5 - Number outside of Section', - input: false, - tableView: false, - components: [ - { - label: 'Number5', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - validate: { - customMessage: 'Value must be greater than Number3', - custom: 'valid = input>data.number3;', - }, - key: 'number6', - type: 'number', - input: true, - }, - ], + label: 'First Name', + placeholder: 'Enter your first Name', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'firstName', + validate: { required: true }, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + hideOnChildrenHidden: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, - ], - }, - { - title: 'Case 6 - Min / Max Date from Today', - collapsible: false, - key: 'case6', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ + ], + width: 5, + offset: 0, + push: 0, + pull: 0, + type: 'column', + input: false, + hideOnChildrenHidden: false, + key: 'column', + tableView: true, + label: 'Column', + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + dataGridLabel: false, + labelPosition: 'top', + labelWidth: 30, + labelMargin: 3, + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + allowCalculateOverride: false, + widget: null, + refreshOn: '', + clearOnRefresh: false, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false }, + conditional: { show: null, when: null, eq: '' }, + id: 'eu6xaap', + size: 'md', + currentWidth: 5, + }, + { + components: [ { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 6:

\n

Date field d should have a date that is at most/least N days/weeks/months/years ago/ from today\n \n

', - refreshOnChange: false, - key: 'html4', - type: 'htmlelement', - input: false, - tableView: false, + label: 'Middle Name', + placeholder: 'Enter your middle name', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'middleName', + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + hideOnChildrenHidden: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, + ], + width: 2, + offset: 0, + push: 0, + pull: 0, + type: 'column', + input: false, + hideOnChildrenHidden: false, + key: 'column', + tableView: true, + label: 'Column', + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + dataGridLabel: false, + labelPosition: 'top', + labelWidth: 30, + labelMargin: 3, + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + allowCalculateOverride: false, + widget: null, + refreshOn: '', + clearOnRefresh: false, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false }, + conditional: { show: null, when: null, eq: '' }, + id: 'eorxgl', + size: 'md', + currentWidth: 2, + }, + { + width: 5, + offset: 0, + push: 0, + pull: 0, + type: 'column', + input: false, + hideOnChildrenHidden: false, + key: 'column', + tableView: true, + label: 'Column', + components: [ { - label: 'Date / Time', - tableView: false, - enableMinDateInput: true, - datePicker: { - disableWeekends: false, - disableWeekdays: false, - maxDate: "moment().add(10, 'days')", - minDate: "moment().subtract(10, 'days')", - }, - enableMaxDateInput: true, - key: 'dateTime', - type: 'datetime', - input: true, - widget: { - type: 'calendar', - displayInTimezone: 'viewer', - locale: 'en', - useLocaleSettings: false, - allowInput: true, - mode: 'single', - enableTime: true, - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - hourIncrement: 1, - minuteIncrement: 1, - time_24hr: false, - minDate: "moment().subtract(10, 'days')", - disableWeekends: false, - disableWeekdays: false, - maxDate: "moment().add(10, 'days')", - }, + label: 'Last Name', + placeholder: 'Enter your last name', + description: 'This is the name that should be on your birth certificate.', + tooltip: 'Seriously? You still need help with this one?', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'lastName', + validate: { required: true }, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + hideOnChildrenHidden: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, - ], - }, - { - type: 'button', - label: 'Submit', - key: 'submit', - disableOnInvalid: true, - input: true, - tableView: false, + ], + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + dataGridLabel: false, + labelPosition: 'top', + labelWidth: 30, + labelMargin: 3, + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + allowCalculateOverride: false, + widget: null, + refreshOn: '', + clearOnRefresh: false, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false }, + conditional: { show: null, when: null, eq: '' }, + id: 'e02wdt8', + size: 'md', + currentWidth: 5, + }, + ], + mask: false, + tableView: false, + alwaysEnabled: false, + type: 'columns', + input: false, + key: 'columns', + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + hideOnChildrenHidden: false, }, - ], - revisions: '', - _vid: 0, - title: 'Validation Rules - NY Health', - display: 'wizard', - access: [ { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', + input: true, + tableView: true, + label: 'Email', + key: 'panel2Email', + type: 'email', + labelWidth: 30, + labelMargin: 3, + widget: { + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + clearOnRefresh: false, + alwaysEnabled: false, }, - ], - submissionAccess: [], - controller: '', - properties: {}, - settings: {}, - name: 'validationRulesNyHealth', - path: 'validationrulesnyhealth', - project: '5692b91fd1028f01000407e3', - created: '2021-10-20T17:28:38.165Z', - modified: '2021-10-20T18:08:13.287Z', - machineName: 'examples:validationRulesNyHealth', -}; - -export const inlineembed = { - _id: '60089c6795f584688609f83c', - type: 'form', - tags: [], - owner: '553dbfc08d22d5cb1a7024f2', - components: [ { - html: '

This is a form that enables the configuration of a Quick Inline Embed for a Form.io form.

For advanced documentation on how to use this embedding feature, please see our Quick Inline Embed Documentation.

', - label: 'Content', - refreshOnChange: false, - key: 'content', - type: 'content', - input: false, - tableView: false, + label: 'Website', + inputMasks: [{ label: '', mask: '' }], + alwaysEnabled: false, + tableView: true, + key: 'website', + type: 'url', + input: true, }, { - label: 'Columns', - columns: [ - { - components: [ - { - title: 'Embed Configuration', - collapsible: false, - key: 'embedConfiguration', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Embed Script', - defaultValue: 'https://cdn.form.io/formiojs/formio.embed.js', - key: 'embed', - type: 'hidden', - tableView: true, - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - }, - { - label: 'Project', - tableView: true, - key: 'project', - type: 'hidden', - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - }, - { - label: 'Base', - tableView: true, - key: 'base', - type: 'hidden', - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - }, - { - label: 'Form URL', - tableView: true, - validate: { required: true }, - key: 'src', - type: 'textfield', - input: true, - defaultValue: 'https://examples.form.io/example', - hideOnChildrenHidden: false, - }, - { - label: 'Template', - widget: 'choicesjs', - tableView: true, - data: { - values: [ - { label: 'Boostrap 4', value: 'false' }, - { label: 'USWDS', value: 'uswds' }, - ], - }, - key: 'template', - type: 'select', - input: true, - searchThreshold: 0.3, - hideOnChildrenHidden: false, - }, - { - title: 'Advanced Settings', - collapsible: true, - key: 'advancedSettings', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Redirect', - tableView: true, - key: 'redirect', - type: 'url', - input: true, - }, - { - label: 'Submission Endpoint', - tableView: true, - key: 'submit', - type: 'url', - input: true, - }, - { - label: 'Inherit Page CSS', - tableView: false, - defaultValue: true, - calculateValue: - 'if (data.encapsulate) {\n value = true;\n}', - key: 'inherit', - type: 'checkbox', - input: true, - }, - { - label: 'Debug Mode', - tableView: false, - key: 'debug', - type: 'checkbox', - input: true, - defaultValue: false, - }, - { - label: 'Custom Configurations', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'config', - type: 'textarea', - as: 'json', - input: true, - }, - { - input: true, - key: 'before', - tableView: true, - label: 'Before Render Handler', - type: 'textarea', - editor: 'ace', - as: 'string', - }, - { - label: 'After Render Handler', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'after', - type: 'textarea', - as: 'string', - input: true, - }, - ], - collapsed: true, - hideOnChildrenHidden: false, - }, - ], - hideOnChildrenHidden: false, - }, - ], - width: 6, - offset: 0, - push: 0, - pull: 0, - size: 'md', - currentWidth: 6, - }, - { - components: [ - { - title: 'Embed Code', - collapsible: false, - key: 'embedCode', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'HTML', - tag: 'pre', - attrs: [{ attr: '', value: '' }], - content: - '', - refreshOnChange: true, - key: 'html', - type: 'htmlelement', - input: false, - tableView: false, - }, - { - label: 'Copy to Clipboard', - action: 'custom', - showValidations: false, - theme: 'success', - block: true, - leftIcon: 'fa fa-copy', - tableView: false, - key: 'copyToClipboard', - type: 'button', - custom: 'var embedCode = document.getElementById(\'embed-code\');\nif (embedCode) {\n embedCode.focus();\n embedCode.select();\n document.execCommand("copy");\n}', - input: true, - hideOnChildrenHidden: false, - }, - ], - hideOnChildrenHidden: false, - }, - ], - width: 6, - offset: 0, - push: 0, - pull: 0, - size: 'md', - currentWidth: 6, - }, - ], - hideOnChildrenHidden: false, - key: 'columns', - type: 'columns', - input: false, - tableView: false, + key: 'panel2Panel', + input: false, + title: 'Other Information', + theme: 'primary', + tableView: false, + components: [ + { + input: true, + tableView: true, + label: 'Phone Number', + key: 'panel2PhoneNumber', + type: 'phoneNumber', + labelWidth: 30, + labelMargin: 3, + widget: { + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + clearOnRefresh: false, + alwaysEnabled: false, + }, + { + input: true, + tableView: false, + inputType: 'password', + label: 'Password', + key: 'panel2Password', + protected: true, + type: 'password', + labelWidth: 30, + labelMargin: 3, + widget: { + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + clearOnRefresh: false, + alwaysEnabled: false, + }, + { + label: 'SSN', + inputMask: '999 - 99 - 9999', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'ssn', + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + input: true, + tableView: true, + label: 'Birthday', + key: 'panel2Birthday', + datePicker: { datepickerMode: 'day' }, + type: 'datetime', + suffix: '\n', + widget: { + type: 'calendar', + displayInTimezone: 'viewer', + locale: 'en', + useLocaleSettings: false, + allowInput: true, + mode: 'single', + enableTime: true, + noCalendar: false, + format: 'yyyy-MM-dd hh:mm a', + hourIncrement: 1, + minuteIncrement: 1, + time_24hr: false, + minDate: null, + maxDate: null, + }, + defaultValue: null, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + alwaysEnabled: false, + }, + { + input: true, + tableView: true, + inputType: 'text', + label: 'Salary', + key: 'salary', + suffix: 'USD', + delimiter: true, + decimalLimit: 2, + requireDecimal: true, + type: 'currency', + tooltip: 'Enter your yearly salary', + description: 'Your yearly earnings before taxes.', + lockKey: true, + labelWidth: 30, + labelMargin: 3, + widget: null, + clearOnRefresh: false, + alwaysEnabled: false, + }, + { + input: true, + tableView: true, + inputType: 'number', + label: 'Number of Pets', + key: 'panel2NumberofPets', + prefix: '#', + type: 'number', + labelWidth: 30, + labelMargin: 3, + widget: null, + clearOnRefresh: false, + alwaysEnabled: false, + }, + { + input: true, + tableView: true, + label: 'Favorite Month', + key: 'panel2FavoriteMonth', + data: { + values: [ + { value: 'january', label: 'January' }, + { value: 'february', label: 'February' }, + { value: 'march', label: 'March' }, + { value: 'april', label: 'April' }, + { value: 'may', label: 'May' }, + { value: 'june', label: 'June' }, + { value: 'july', label: 'July' }, + { value: 'august', label: 'August' }, + { value: 'september', label: 'September' }, + { value: 'october', label: 'October' }, + { value: 'november', label: 'November' }, + { value: 'december', label: 'December' }, + ], + }, + valueProperty: 'value', + defaultValue: 'may', + type: 'select', + labelWidth: 30, + labelMargin: 3, + alwaysEnabled: false, + }, + { + input: true, + tableView: true, + label: 'Favorite Things', + key: 'panel2FavoriteThings', + data: { + values: [ + { value: 'raindropsOnRoses', label: 'Raindrops on roses' }, + { value: 'whiskersOnKittens', label: 'Whiskers on Kittens' }, + { + value: 'brightCopperKettles', + label: 'Bright Copper Kettles', + }, + { value: 'warmWoolenMittens', label: 'Warm Woolen Mittens' }, + ], + }, + valueProperty: 'value', + multiple: true, + type: 'select', + labelWidth: 30, + labelMargin: 3, + alwaysEnabled: false, + }, + { + input: true, + tableView: true, + label: 'Message', + key: 'panel2PanelMessage', + type: 'textarea', + inputFormat: 'plain', + }, + { + input: true, + tableView: true, + label: 'Favorite Color', + key: 'panel2FavoriteColor', + values: [ + { value: 'blue', label: 'Blue', shortcut: '' }, + { value: 'red', label: 'Red', shortcut: '' }, + { value: 'green', label: 'Green', shortcut: '' }, + { value: 'yellow', label: 'Yellow', shortcut: '' }, + { value: 'purple', label: 'Purple', shortcut: '' }, + { value: 'orange', label: 'Orange', shortcut: '' }, + ], + type: 'radio', + optionsLabelPosition: 'right', + tooltip: 'Select your favorite color.', + inline: true, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + alwaysEnabled: false, + }, + { + input: true, + tableView: true, + label: 'Favorite Fruits', + key: 'panel2FavoriteFruits', + values: [ + { value: 'apple', label: 'Apple', shortcut: '' }, + { value: 'orange', label: 'Orange', shortcut: '' }, + { value: 'banana', label: 'Banana', shortcut: '' }, + { value: 'peach', label: 'Peach', shortcut: '' }, + { value: 'strawberry', label: 'Strawberry', shortcut: '' }, + ], + type: 'selectboxes', + optionsLabelPosition: 'right', + inputType: 'checkbox', + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + alwaysEnabled: false, + }, + ], + type: 'panel', + collapsible: true, + collapsed: true, + label: 'Panel', }, - ], - revisions: '', - _vid: 0, - title: 'Quick Inline Embed', - display: 'form', - access: [ { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', + label: 'Bio', + editor: 'ckeditor', + tableView: true, + alwaysEnabled: false, + wysiwyg: { + theme: 'snow', + placeholder: '', + modules: { + clipboard: { matchVisual: false }, + toolbar: [ + [{ size: ['small', false, 'large', 'huge'] }], + [{ header: [1, 2, 3, 4, 5, 6, false] }], + [{ font: [] }], + [ + 'bold', + 'italic', + 'underline', + 'strike', + { script: 'sub' }, + { script: 'super' }, + 'clean', + ], + [{ color: [] }, { background: [] }], + [ + { list: 'ordered' }, + { list: 'bullet' }, + { indent: '-1' }, + { indent: '+1' }, + { align: [] }, + ], + ['blockquote', 'code-block'], + ['link', 'image', 'video', 'formula', 'source'], + ], + }, + rows: 10, + base64Upload: true, + image: { + toolbar: [ + 'imageTextAlternative', + '|', + 'imageStyle:alignLeft', + 'imageStyle:alignCenter', + 'imageStyle:full', + 'imageStyle:alignRight', + ], + styles: ['full', 'side', 'alignLeft', 'alignCenter', 'alignRight'], + }, + disableNativeSpellChecker: false, + mediaEmbed: { previewsInData: true }, + }, + rows: 10, + type: 'textarea', + input: true, + key: 'bio', + defaultValue: '


', + inputFormat: 'plain', + autoExpand: false, + isUploadEnabled: false, + reorder: false, + widget: { + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, - ], - submissionAccess: [], - controller: '', - properties: {}, - settings: {}, - name: 'inlineembed', - path: 'embed', - project: '5692b91fd1028f01000407e3', - created: '2021-01-20T21:11:03.957Z', - modified: '2021-10-18T16:34:28.512Z', - machineName: 'examples:inlineEmbedConfiguration', -}; - -export const customerLoad = { - _id: '5aa316c59f3918304b469e82', - title: 'Customer Load', - display: 'form', - type: 'form', - components: [ + ], + collapsed: false, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + path: 'panel2', + }, + { + label: 'Education', + reorder: false, + mask: false, + tableView: true, + alwaysEnabled: false, + type: 'editgrid', + input: true, + key: 'education', + components: [ { - input: true, - tableView: true, - inputType: 'number', - label: 'Customer Number', - key: 'customerNumber', - validate: { required: true, min: 1, max: 9 }, - type: 'number', + label: 'School', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'school', + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, - { input: true, tableView: true, label: 'Name', key: 'name', type: 'textfield' }, { - input: true, - tableView: true, - label: 'Phone Number', - key: 'phoneNumber', - type: 'textfield', + label: 'Degree', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'degree', + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, - { input: true, label: 'Submit', tableView: false, key: 'submit', type: 'button' }, - ], - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - '000000000000000000000000', - ], - type: 'read_all', + label: 'Graduation Date', + hideInputLabels: false, + inputsLabelPosition: 'top', + fields: { day: { hide: false }, month: { hide: false }, year: { hide: false } }, + useLocaleSettings: false, + mask: false, + tableView: true, + alwaysEnabled: false, + type: 'day', + input: true, + key: 'graduationDate', + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - submissionAccess: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - settings: {}, - name: 'customerLoad', - path: 'customerload', - owner: '55673dc04f0405dd28205bb7', - project: '5692b91fd1028f01000407e3', - tags: [], - created: '2018-03-09T23:20:37.966Z', - revisions: '', - _vid: 0, - modified: '2021-09-15T17:09:44.770Z', - machineName: 'examples:customerLoad', -}; - -export const kitchenSink = { - _id: '5d7a42f21cc1c2ca88ff2dd5', - type: 'form', - tags: [], - owner: '553dbfc08d22d5cb1a7024f2', - components: [ + ], + templates: { + header: + '
\n {%util.eachComponent(components, function(component) { %} \n
\n {{ component.label }} \n
\n {% }) %} \n
', + row: '
\n {% util.eachComponent(components, function(component) { %}\n
\n {{ getView(component, row[component.key]) }}\n
\n {% }) %}\n {% if (!instance.options.readOnly) { %}\n
\n
\n \n \n
\n
\n {% } %}\n
', + }, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + removeRow: '', + }, + { + label: 'Survey', + alwaysEnabled: false, + tableView: false, + questions: [ + { label: 'Food', value: 'food' }, + { label: 'Experience', value: 'experience' }, + { label: 'Restrooms', value: 'restrooms' }, + { label: 'Staff', value: 'staff' }, + ], + values: [ + { label: 'Very Good', value: 'veryGood' }, + { label: 'Good', value: 'good' }, + { label: 'Average', value: 'average' }, + { label: 'Bad', value: 'bad' }, + { label: 'Awful', value: 'awful' }, + ], + key: 'survey1', + type: 'survey', + input: true, + }, + { + label: 'Children', + alwaysEnabled: false, + tableView: false, + key: 'children', + type: 'well', + input: false, + components: [ { - label: 'Panel', - title: 'User Information', - collapsible: false, - mask: false, - tableView: false, - alwaysEnabled: false, - type: 'panel', - input: false, - key: 'panel2', - components: [ - { - label: 'Columns', - columns: [ - { - components: [ - { - label: 'First Name', - placeholder: 'Enter your first Name', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'firstName', - validate: { required: true }, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - hideOnChildrenHidden: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - width: 5, - offset: 0, - push: 0, - pull: 0, - type: 'column', - input: false, - hideOnChildrenHidden: false, - key: 'column', - tableView: true, - label: 'Column', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - dataGridLabel: false, - labelPosition: 'top', - labelWidth: 30, - labelMargin: 3, - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - allowCalculateOverride: false, - widget: null, - refreshOn: '', - clearOnRefresh: false, - validateOn: 'change', - validate: { required: false, custom: '', customPrivate: false }, - conditional: { show: null, when: null, eq: '' }, - id: 'eu6xaap', - size: 'md', - currentWidth: 5, - }, - { - components: [ - { - label: 'Middle Name', - placeholder: 'Enter your middle name', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'middleName', - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - hideOnChildrenHidden: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - width: 2, - offset: 0, - push: 0, - pull: 0, - type: 'column', - input: false, - hideOnChildrenHidden: false, - key: 'column', - tableView: true, - label: 'Column', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - dataGridLabel: false, - labelPosition: 'top', - labelWidth: 30, - labelMargin: 3, - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - allowCalculateOverride: false, - widget: null, - refreshOn: '', - clearOnRefresh: false, - validateOn: 'change', - validate: { required: false, custom: '', customPrivate: false }, - conditional: { show: null, when: null, eq: '' }, - id: 'eorxgl', - size: 'md', - currentWidth: 2, - }, - { - width: 5, - offset: 0, - push: 0, - pull: 0, - type: 'column', - input: false, - hideOnChildrenHidden: false, - key: 'column', - tableView: true, - label: 'Column', - components: [ - { - label: 'Last Name', - placeholder: 'Enter your last name', - description: - 'This is the name that should be on your birth certificate.', - tooltip: 'Seriously? You still need help with this one?', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'lastName', - validate: { required: true }, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - hideOnChildrenHidden: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - dataGridLabel: false, - labelPosition: 'top', - labelWidth: 30, - labelMargin: 3, - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - allowCalculateOverride: false, - widget: null, - refreshOn: '', - clearOnRefresh: false, - validateOn: 'change', - validate: { required: false, custom: '', customPrivate: false }, - conditional: { show: null, when: null, eq: '' }, - id: 'e02wdt8', - size: 'md', - currentWidth: 5, - }, - ], - mask: false, - tableView: false, - alwaysEnabled: false, - type: 'columns', - input: false, - key: 'columns', - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - hideOnChildrenHidden: false, - }, - { - input: true, - tableView: true, - label: 'Email', - key: 'panel2Email', - type: 'email', - labelWidth: 30, - labelMargin: 3, - widget: { - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', + label: 'Children', + reorder: false, + addAnotherPosition: 'bottom', + defaultOpen: false, + layoutFixed: false, + enableRowGroups: false, + alwaysEnabled: false, + tableView: false, + key: 'children', + type: 'datagrid', + input: true, + components: [ + { + label: 'First Name', + widget: { + i18n: { + lng: 'en', + resources: { + en: { + translation: { + complete: 'Submission Complete', + error: 'Please fix the following errors before submitting.', + required: '{{field}} is required', + pattern: '{{field}} does not match the pattern {{pattern}}', + minLength: '{{field}} must be longer than {{length}} characters.', + maxLength: '{{field}} must be shorter than {{length}} characters.', + minWords: '{{field}} must have more than {{length}} words.', + maxWords: '{{field}} must have less than {{length}} words.', + min: '{{field}} cannot be less than {{min}}.', + max: '{{field}} cannot be greater than {{max}}.', + minSelectedCount: + 'You must select at least {{minCount}} items to continue.', + maxSelectedCount: + 'You can only select up to {{maxCount}} items to continue.', + maxDate: '{{field}} should not contain date after {{- maxDate}}', + minDate: '{{field}} should not contain date before {{- minDate}}', + invalid_email: '{{field}} must be a valid email.', + invalid_url: '{{field}} must be a valid url.', + invalid_regex: '{{field}} does not match the pattern {{regex}}.', + invalid_date: '{{field}} is not a valid date.', + invalid_day: '{{field}} is not a valid day.', + mask: '{{field}} does not match the mask.', + stripe: '{{stripe}}', + month: 'Month', + day: 'Day', + year: 'Year', + january: 'January', + february: 'February', + march: 'March', + april: 'April', + may: 'May', + june: 'June', + july: 'July', + august: 'August', + september: 'September', + october: 'October', + november: 'November', + december: 'December', + next: 'Next', + previous: 'Previous', + cancel: 'Cancel', + submit: 'Submit Form', + }, }, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - label: 'Website', - inputMasks: [{ label: '', mask: '' }], - alwaysEnabled: false, - tableView: true, - key: 'website', - type: 'url', - input: true, - }, - { - key: 'panel2Panel', - input: false, - title: 'Other Information', - theme: 'primary', - tableView: false, - components: [ - { - input: true, - tableView: true, - label: 'Phone Number', - key: 'panel2PhoneNumber', - type: 'phoneNumber', - labelWidth: 30, - labelMargin: 3, - widget: { - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: false, - inputType: 'password', - label: 'Password', - key: 'panel2Password', - protected: true, - type: 'password', - labelWidth: 30, - labelMargin: 3, - widget: { - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - label: 'SSN', - inputMask: '999 - 99 - 9999', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'ssn', - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - input: true, - tableView: true, - label: 'Birthday', - key: 'panel2Birthday', - datePicker: { datepickerMode: 'day' }, - type: 'datetime', - suffix: '\n', - widget: { - type: 'calendar', - displayInTimezone: 'viewer', - locale: 'en', - useLocaleSettings: false, - allowInput: true, - mode: 'single', - enableTime: true, - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - hourIncrement: 1, - minuteIncrement: 1, - time_24hr: false, - minDate: null, - maxDate: null, - }, - defaultValue: null, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - inputType: 'text', - label: 'Salary', - key: 'salary', - suffix: 'USD', - delimiter: true, - decimalLimit: 2, - requireDecimal: true, - type: 'currency', - tooltip: 'Enter your yearly salary', - description: 'Your yearly earnings before taxes.', - lockKey: true, - labelWidth: 30, - labelMargin: 3, - widget: null, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - inputType: 'number', - label: 'Number of Pets', - key: 'panel2NumberofPets', - prefix: '#', - type: 'number', - labelWidth: 30, - labelMargin: 3, - widget: null, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Favorite Month', - key: 'panel2FavoriteMonth', - data: { - values: [ - { value: 'january', label: 'January' }, - { value: 'february', label: 'February' }, - { value: 'march', label: 'March' }, - { value: 'april', label: 'April' }, - { value: 'may', label: 'May' }, - { value: 'june', label: 'June' }, - { value: 'july', label: 'July' }, - { value: 'august', label: 'August' }, - { value: 'september', label: 'September' }, - { value: 'october', label: 'October' }, - { value: 'november', label: 'November' }, - { value: 'december', label: 'December' }, - ], - }, - valueProperty: 'value', - defaultValue: 'may', - type: 'select', - labelWidth: 30, - labelMargin: 3, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Favorite Things', - key: 'panel2FavoriteThings', - data: { - values: [ - { value: 'raindropsOnRoses', label: 'Raindrops on roses' }, - { value: 'whiskersOnKittens', label: 'Whiskers on Kittens' }, - { - value: 'brightCopperKettles', - label: 'Bright Copper Kettles', - }, - { value: 'warmWoolenMittens', label: 'Warm Woolen Mittens' }, - ], - }, - valueProperty: 'value', - multiple: true, - type: 'select', - labelWidth: 30, - labelMargin: 3, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Message', - key: 'panel2PanelMessage', - type: 'textarea', - inputFormat: 'plain', - }, - { - input: true, - tableView: true, - label: 'Favorite Color', - key: 'panel2FavoriteColor', - values: [ - { value: 'blue', label: 'Blue', shortcut: '' }, - { value: 'red', label: 'Red', shortcut: '' }, - { value: 'green', label: 'Green', shortcut: '' }, - { value: 'yellow', label: 'Yellow', shortcut: '' }, - { value: 'purple', label: 'Purple', shortcut: '' }, - { value: 'orange', label: 'Orange', shortcut: '' }, - ], - type: 'radio', - optionsLabelPosition: 'right', - tooltip: 'Select your favorite color.', - inline: true, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Favorite Fruits', - key: 'panel2FavoriteFruits', - values: [ - { value: 'apple', label: 'Apple', shortcut: '' }, - { value: 'orange', label: 'Orange', shortcut: '' }, - { value: 'banana', label: 'Banana', shortcut: '' }, - { value: 'peach', label: 'Peach', shortcut: '' }, - { value: 'strawberry', label: 'Strawberry', shortcut: '' }, - ], - type: 'selectboxes', - optionsLabelPosition: 'right', - inputType: 'checkbox', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - ], - type: 'panel', - collapsible: true, - collapsed: true, - label: 'Panel', + }, }, - { - label: 'Bio', - editor: 'ckeditor', - tableView: true, - alwaysEnabled: false, - wysiwyg: { - theme: 'snow', - placeholder: '', - modules: { - clipboard: { matchVisual: false }, - toolbar: [ - [{ size: ['small', false, 'large', 'huge'] }], - [{ header: [1, 2, 3, 4, 5, 6, false] }], - [{ font: [] }], - [ - 'bold', - 'italic', - 'underline', - 'strike', - { script: 'sub' }, - { script: 'super' }, - 'clean', - ], - [{ color: [] }, { background: [] }], - [ - { list: 'ordered' }, - { list: 'bullet' }, - { indent: '-1' }, - { indent: '+1' }, - { align: [] }, - ], - ['blockquote', 'code-block'], - ['link', 'image', 'video', 'formula', 'source'], - ], - }, - rows: 10, - base64Upload: true, - image: { - toolbar: [ - 'imageTextAlternative', - '|', - 'imageStyle:alignLeft', - 'imageStyle:alignCenter', - 'imageStyle:full', - 'imageStyle:alignRight', - ], - styles: ['full', 'side', 'alignLeft', 'alignCenter', 'alignRight'], - }, - disableNativeSpellChecker: false, - mediaEmbed: { previewsInData: true }, - }, - rows: 10, - type: 'textarea', - input: true, - key: 'bio', - defaultValue: '


', - inputFormat: 'plain', - autoExpand: false, - isUploadEnabled: false, - reorder: false, - widget: { - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', + language: 'en', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + alwaysEnabled: false, + tableView: true, + key: 'firstName', + type: 'textfield', + input: true, + inDataGrid: true, + row: '0-0', + }, + { + label: 'Last Name', + widget: { + i18n: { + lng: 'en', + resources: { + en: { + translation: { + complete: 'Submission Complete', + error: 'Please fix the following errors before submitting.', + required: '{{field}} is required', + pattern: '{{field}} does not match the pattern {{pattern}}', + minLength: '{{field}} must be longer than {{length}} characters.', + maxLength: '{{field}} must be shorter than {{length}} characters.', + minWords: '{{field}} must have more than {{length}} words.', + maxWords: '{{field}} must have less than {{length}} words.', + min: '{{field}} cannot be less than {{min}}.', + max: '{{field}} cannot be greater than {{max}}.', + minSelectedCount: + 'You must select at least {{minCount}} items to continue.', + maxSelectedCount: + 'You can only select up to {{maxCount}} items to continue.', + maxDate: '{{field}} should not contain date after {{- maxDate}}', + minDate: '{{field}} should not contain date before {{- minDate}}', + invalid_email: '{{field}} must be a valid email.', + invalid_url: '{{field}} must be a valid url.', + invalid_regex: '{{field}} does not match the pattern {{regex}}.', + invalid_date: '{{field}} is not a valid date.', + invalid_day: '{{field}} is not a valid day.', + mask: '{{field}} does not match the mask.', + stripe: '{{stripe}}', + month: 'Month', + day: 'Day', + year: 'Year', + january: 'January', + february: 'February', + march: 'March', + april: 'April', + may: 'May', + june: 'June', + july: 'July', + august: 'August', + september: 'September', + october: 'October', + november: 'November', + december: 'December', + next: 'Next', + previous: 'Previous', + cancel: 'Cancel', + submit: 'Submit Form', + }, }, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, + }, }, - ], - collapsed: false, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - path: 'panel2', + language: 'en', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + alwaysEnabled: false, + tableView: true, + key: 'lastName', + type: 'textfield', + input: true, + inDataGrid: true, + row: '0-1', + }, + ], + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, + ], + path: 'children', + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + title: 'Guardian Information', + collapsible: false, + alwaysEnabled: false, + tableView: false, + key: 'guardianInformation', + type: 'panel', + input: false, + label: 'Panel', + components: [ { - label: 'Education', - reorder: false, - mask: false, - tableView: true, - alwaysEnabled: false, - type: 'editgrid', - input: true, - key: 'education', - components: [ - { - label: 'School', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'school', - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', + label: 'Guardian', + alwaysEnabled: false, + tableView: false, + key: 'guardian', + type: 'container', + input: true, + components: [ + { + label: 'First Name', + widget: { + i18n: { + lng: 'en', + resources: { + en: { + translation: { + complete: 'Submission Complete', + error: 'Please fix the following errors before submitting.', + required: '{{field}} is required', + pattern: '{{field}} does not match the pattern {{pattern}}', + minLength: '{{field}} must be longer than {{length}} characters.', + maxLength: '{{field}} must be shorter than {{length}} characters.', + minWords: '{{field}} must have more than {{length}} words.', + maxWords: '{{field}} must have less than {{length}} words.', + min: '{{field}} cannot be less than {{min}}.', + max: '{{field}} cannot be greater than {{max}}.', + minSelectedCount: + 'You must select at least {{minCount}} items to continue.', + maxSelectedCount: + 'You can only select up to {{maxCount}} items to continue.', + maxDate: '{{field}} should not contain date after {{- maxDate}}', + minDate: '{{field}} should not contain date before {{- minDate}}', + invalid_email: '{{field}} must be a valid email.', + invalid_url: '{{field}} must be a valid url.', + invalid_regex: '{{field}} does not match the pattern {{regex}}.', + invalid_date: '{{field}} is not a valid date.', + invalid_day: '{{field}} is not a valid day.', + mask: '{{field}} does not match the mask.', + stripe: '{{stripe}}', + month: 'Month', + day: 'Day', + year: 'Year', + january: 'January', + february: 'February', + march: 'March', + april: 'April', + may: 'May', + june: 'June', + july: 'July', + august: 'August', + september: 'September', + october: 'October', + november: 'November', + december: 'December', + next: 'Next', + previous: 'Previous', + cancel: 'Cancel', + submit: 'Submit Form', + }, }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, + }, }, - { - label: 'Degree', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'degree', - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', + language: 'en', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + alwaysEnabled: false, + tableView: true, + key: 'firstName1', + type: 'textfield', + input: true, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + label: 'Last Name', + widget: { + i18n: { + lng: 'en', + resources: { + en: { + translation: { + complete: 'Submission Complete', + error: 'Please fix the following errors before submitting.', + required: '{{field}} is required', + pattern: '{{field}} does not match the pattern {{pattern}}', + minLength: '{{field}} must be longer than {{length}} characters.', + maxLength: '{{field}} must be shorter than {{length}} characters.', + minWords: '{{field}} must have more than {{length}} words.', + maxWords: '{{field}} must have less than {{length}} words.', + min: '{{field}} cannot be less than {{min}}.', + max: '{{field}} cannot be greater than {{max}}.', + minSelectedCount: + 'You must select at least {{minCount}} items to continue.', + maxSelectedCount: + 'You can only select up to {{maxCount}} items to continue.', + maxDate: '{{field}} should not contain date after {{- maxDate}}', + minDate: '{{field}} should not contain date before {{- minDate}}', + invalid_email: '{{field}} must be a valid email.', + invalid_url: '{{field}} must be a valid url.', + invalid_regex: '{{field}} does not match the pattern {{regex}}.', + invalid_date: '{{field}} is not a valid date.', + invalid_day: '{{field}} is not a valid day.', + mask: '{{field}} does not match the mask.', + stripe: '{{stripe}}', + month: 'Month', + day: 'Day', + year: 'Year', + january: 'January', + february: 'February', + march: 'March', + april: 'April', + may: 'May', + june: 'June', + july: 'July', + august: 'August', + september: 'September', + october: 'October', + november: 'November', + december: 'December', + next: 'Next', + previous: 'Previous', + cancel: 'Cancel', + submit: 'Submit Form', + }, }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Graduation Date', - hideInputLabels: false, - inputsLabelPosition: 'top', - fields: { day: { hide: false }, month: { hide: false }, year: { hide: false } }, - useLocaleSettings: false, - mask: false, - tableView: true, - alwaysEnabled: false, - type: 'day', - input: true, - key: 'graduationDate', - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, + }, }, - ], - templates: { - header: '
\n {%util.eachComponent(components, function(component) { %} \n
\n {{ component.label }} \n
\n {% }) %} \n
', - row: '
\n {% util.eachComponent(components, function(component) { %}\n
\n {{ getView(component, row[component.key]) }}\n
\n {% }) %}\n {% if (!instance.options.readOnly) { %}\n
\n
\n \n \n
\n
\n {% } %}\n
', + language: 'en', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + alwaysEnabled: false, + tableView: true, + key: 'lastName1', + type: 'textfield', + input: true, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - removeRow: '', - }, - { - label: 'Survey', - alwaysEnabled: false, - tableView: false, - questions: [ - { label: 'Food', value: 'food' }, - { label: 'Experience', value: 'experience' }, - { label: 'Restrooms', value: 'restrooms' }, - { label: 'Staff', value: 'staff' }, - ], - values: [ - { label: 'Very Good', value: 'veryGood' }, - { label: 'Good', value: 'good' }, - { label: 'Average', value: 'average' }, - { label: 'Bad', value: 'bad' }, - { label: 'Awful', value: 'awful' }, - ], - key: 'survey1', - type: 'survey', - input: true, + ], + path: 'guardian', + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, + ], + path: 'guardianInformation', + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + label: 'Tabs', + components: [ { - label: 'Children', - alwaysEnabled: false, - tableView: false, - key: 'children', - type: 'well', - input: false, - components: [ - { - label: 'Children', - reorder: false, - addAnotherPosition: 'bottom', - defaultOpen: false, - layoutFixed: false, - enableRowGroups: false, - alwaysEnabled: false, - tableView: false, - key: 'children', - type: 'datagrid', - input: true, - components: [ - { - label: 'First Name', - widget: { - i18n: { - lng: 'en', - resources: { - en: { - translation: { - complete: 'Submission Complete', - error: 'Please fix the following errors before submitting.', - required: '{{field}} is required', - pattern: - '{{field}} does not match the pattern {{pattern}}', - minLength: - '{{field}} must be longer than {{length}} characters.', - maxLength: - '{{field}} must be shorter than {{length}} characters.', - minWords: - '{{field}} must have more than {{length}} words.', - maxWords: - '{{field}} must have less than {{length}} words.', - min: '{{field}} cannot be less than {{min}}.', - max: '{{field}} cannot be greater than {{max}}.', - minSelectedCount: - 'You must select at least {{minCount}} items to continue.', - maxSelectedCount: - 'You can only select up to {{maxCount}} items to continue.', - maxDate: - '{{field}} should not contain date after {{- maxDate}}', - minDate: - '{{field}} should not contain date before {{- minDate}}', - invalid_email: '{{field}} must be a valid email.', - invalid_url: '{{field}} must be a valid url.', - invalid_regex: - '{{field}} does not match the pattern {{regex}}.', - invalid_date: '{{field}} is not a valid date.', - invalid_day: '{{field}} is not a valid day.', - mask: '{{field}} does not match the mask.', - stripe: '{{stripe}}', - month: 'Month', - day: 'Day', - year: 'Year', - january: 'January', - february: 'February', - march: 'March', - april: 'April', - may: 'May', - june: 'June', - july: 'July', - august: 'August', - september: 'September', - october: 'October', - november: 'November', - december: 'December', - next: 'Next', - previous: 'Previous', - cancel: 'Cancel', - submit: 'Submit Form', - }, - }, - }, - }, - language: 'en', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - alwaysEnabled: false, - tableView: true, - key: 'firstName', - type: 'textfield', - input: true, - inDataGrid: true, - row: '0-0', - }, - { - label: 'Last Name', - widget: { - i18n: { - lng: 'en', - resources: { - en: { - translation: { - complete: 'Submission Complete', - error: 'Please fix the following errors before submitting.', - required: '{{field}} is required', - pattern: - '{{field}} does not match the pattern {{pattern}}', - minLength: - '{{field}} must be longer than {{length}} characters.', - maxLength: - '{{field}} must be shorter than {{length}} characters.', - minWords: - '{{field}} must have more than {{length}} words.', - maxWords: - '{{field}} must have less than {{length}} words.', - min: '{{field}} cannot be less than {{min}}.', - max: '{{field}} cannot be greater than {{max}}.', - minSelectedCount: - 'You must select at least {{minCount}} items to continue.', - maxSelectedCount: - 'You can only select up to {{maxCount}} items to continue.', - maxDate: - '{{field}} should not contain date after {{- maxDate}}', - minDate: - '{{field}} should not contain date before {{- minDate}}', - invalid_email: '{{field}} must be a valid email.', - invalid_url: '{{field}} must be a valid url.', - invalid_regex: - '{{field}} does not match the pattern {{regex}}.', - invalid_date: '{{field}} is not a valid date.', - invalid_day: '{{field}} is not a valid day.', - mask: '{{field}} does not match the mask.', - stripe: '{{stripe}}', - month: 'Month', - day: 'Day', - year: 'Year', - january: 'January', - february: 'February', - march: 'March', - april: 'April', - may: 'May', - june: 'June', - july: 'July', - august: 'August', - september: 'September', - october: 'October', - november: 'November', - december: 'December', - next: 'Next', - previous: 'Previous', - cancel: 'Cancel', - submit: 'Submit Form', - }, - }, - }, - }, - language: 'en', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - alwaysEnabled: false, - tableView: true, - key: 'lastName', - type: 'textfield', - input: true, - inDataGrid: true, - row: '0-1', - }, - ], - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - path: 'children', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, + label: 'Tab 1', + key: 'tab1', + components: [ + { + label: 'One', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'one', + tab: 0, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + label: 'Two', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'two', + tab: 0, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + label: 'Tags', + alwaysEnabled: false, + tableView: false, + key: 'tags1', + type: 'tags', + input: true, + }, + ], }, { - title: 'Guardian Information', - collapsible: false, - alwaysEnabled: false, - tableView: false, - key: 'guardianInformation', - type: 'panel', - input: false, - label: 'Panel', - components: [ - { - label: 'Guardian', - alwaysEnabled: false, - tableView: false, - key: 'guardian', - type: 'container', - input: true, - components: [ - { - label: 'First Name', - widget: { - i18n: { - lng: 'en', - resources: { - en: { - translation: { - complete: 'Submission Complete', - error: 'Please fix the following errors before submitting.', - required: '{{field}} is required', - pattern: - '{{field}} does not match the pattern {{pattern}}', - minLength: - '{{field}} must be longer than {{length}} characters.', - maxLength: - '{{field}} must be shorter than {{length}} characters.', - minWords: - '{{field}} must have more than {{length}} words.', - maxWords: - '{{field}} must have less than {{length}} words.', - min: '{{field}} cannot be less than {{min}}.', - max: '{{field}} cannot be greater than {{max}}.', - minSelectedCount: - 'You must select at least {{minCount}} items to continue.', - maxSelectedCount: - 'You can only select up to {{maxCount}} items to continue.', - maxDate: - '{{field}} should not contain date after {{- maxDate}}', - minDate: - '{{field}} should not contain date before {{- minDate}}', - invalid_email: '{{field}} must be a valid email.', - invalid_url: '{{field}} must be a valid url.', - invalid_regex: - '{{field}} does not match the pattern {{regex}}.', - invalid_date: '{{field}} is not a valid date.', - invalid_day: '{{field}} is not a valid day.', - mask: '{{field}} does not match the mask.', - stripe: '{{stripe}}', - month: 'Month', - day: 'Day', - year: 'Year', - january: 'January', - february: 'February', - march: 'March', - april: 'April', - may: 'May', - june: 'June', - july: 'July', - august: 'August', - september: 'September', - october: 'October', - november: 'November', - december: 'December', - next: 'Next', - previous: 'Previous', - cancel: 'Cancel', - submit: 'Submit Form', - }, - }, - }, - }, - language: 'en', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - alwaysEnabled: false, - tableView: true, - key: 'firstName1', - type: 'textfield', - input: true, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Last Name', - widget: { - i18n: { - lng: 'en', - resources: { - en: { - translation: { - complete: 'Submission Complete', - error: 'Please fix the following errors before submitting.', - required: '{{field}} is required', - pattern: - '{{field}} does not match the pattern {{pattern}}', - minLength: - '{{field}} must be longer than {{length}} characters.', - maxLength: - '{{field}} must be shorter than {{length}} characters.', - minWords: - '{{field}} must have more than {{length}} words.', - maxWords: - '{{field}} must have less than {{length}} words.', - min: '{{field}} cannot be less than {{min}}.', - max: '{{field}} cannot be greater than {{max}}.', - minSelectedCount: - 'You must select at least {{minCount}} items to continue.', - maxSelectedCount: - 'You can only select up to {{maxCount}} items to continue.', - maxDate: - '{{field}} should not contain date after {{- maxDate}}', - minDate: - '{{field}} should not contain date before {{- minDate}}', - invalid_email: '{{field}} must be a valid email.', - invalid_url: '{{field}} must be a valid url.', - invalid_regex: - '{{field}} does not match the pattern {{regex}}.', - invalid_date: '{{field}} is not a valid date.', - invalid_day: '{{field}} is not a valid day.', - mask: '{{field}} does not match the mask.', - stripe: '{{stripe}}', - month: 'Month', - day: 'Day', - year: 'Year', - january: 'January', - february: 'February', - march: 'March', - april: 'April', - may: 'May', - june: 'June', - july: 'July', - august: 'August', - september: 'September', - october: 'October', - november: 'November', - december: 'December', - next: 'Next', - previous: 'Previous', - cancel: 'Cancel', - submit: 'Submit Form', - }, - }, - }, - }, - language: 'en', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - alwaysEnabled: false, - tableView: true, - key: 'lastName1', - type: 'textfield', - input: true, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - path: 'guardian', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - path: 'guardianInformation', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, + label: 'Tab 2', + key: 'tab2', + components: [ + { + label: 'Three', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'three', + tab: 1, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + label: 'Four', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'four', + tab: 1, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + ], }, { - label: 'Tabs', - components: [ - { - label: 'Tab 1', - key: 'tab1', - components: [ - { - label: 'One', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'one', - tab: 0, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Two', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'two', - tab: 0, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Tags', - alwaysEnabled: false, - tableView: false, - key: 'tags1', - type: 'tags', - input: true, - }, - ], - }, - { - label: 'Tab 2', - key: 'tab2', - components: [ - { - label: 'Three', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'three', - tab: 1, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Four', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'four', - tab: 1, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - }, - { - label: 'Tab 3', - key: 'tab3', - components: [ - { - label: 'Five', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'five', - tab: 2, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Six', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'six', - tab: 2, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - }, - ], - mask: false, - tableView: true, - alwaysEnabled: false, - type: 'tabs', - input: false, - key: 'tabs2', - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - path: 'tabs2', + label: 'Tab 3', + key: 'tab3', + components: [ + { + label: 'Five', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'five', + tab: 2, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + label: 'Six', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'six', + tab: 2, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + ], }, + ], + mask: false, + tableView: true, + alwaysEnabled: false, + type: 'tabs', + input: false, + key: 'tabs2', + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + path: 'tabs2', + }, + { + clearOnHide: false, + key: 'fieldset', + input: false, + tableView: false, + legend: 'Signature', + components: [ { - clearOnHide: false, - key: 'fieldset', - input: false, - tableView: false, - legend: 'Signature', - components: [ - { - key: 'fieldsetContent', - input: false, - html: '

This is some content

\n\n

Click the following if you agree to the rules.

\n\n
    \n\t
  • This
  • \n\t
  • is
  • \n\t
  • an
  • \n\t
  • important
  • \n\t
  • list
  • \n
\n', - type: 'content', - tableView: true, - label: 'Content', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'I agree to the rules', - dataGridLabel: false, - key: 'fieldsetIagreetotherules', - defaultValue: false, - type: 'checkbox', - tooltip: 'Check this if you agree.', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Signature', - key: 'fieldsetSignature', - type: 'signature', - hideLabel: true, - labelWidth: 30, - labelMargin: 3, - widget: null, - clearOnRefresh: false, - alwaysEnabled: false, - }, - ], - type: 'fieldset', - hideLabel: true, - label: 'Field Set', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, + key: 'fieldsetContent', + input: false, + html: '

This is some content

\n\n

Click the following if you agree to the rules.

\n\n
    \n\t
  • This
  • \n\t
  • is
  • \n\t
  • an
  • \n\t
  • important
  • \n\t
  • list
  • \n
\n', + type: 'content', + tableView: true, + label: 'Content', + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + alwaysEnabled: false, }, { - type: 'button', - label: 'Submit', - key: 'submit', - disableOnInvalid: true, - input: true, - tableView: true, - alwaysEnabled: false, - labelWidth: 30, - labelMargin: 3, - widget: null, - clearOnRefresh: false, + input: true, + tableView: true, + label: 'I agree to the rules', + dataGridLabel: false, + key: 'fieldsetIagreetotherules', + defaultValue: false, + type: 'checkbox', + tooltip: 'Check this if you agree.', + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + alwaysEnabled: false, }, - ], - revisions: '', - _vid: 0, - title: 'Kitchen Sink', - display: 'form', - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', + input: true, + tableView: true, + label: 'Signature', + key: 'fieldsetSignature', + type: 'signature', + hideLabel: true, + labelWidth: 30, + labelMargin: 3, + widget: null, + clearOnRefresh: false, + alwaysEnabled: false, }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - submissionAccess: [ - { roles: ['5692b920d1028f01000407e6'], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - settings: {}, - properties: {}, - name: 'kitchenSink', - path: 'kitchensink', - project: '5692b91fd1028f01000407e3', - created: '2019-09-12T13:06:58.622Z', - modified: '2021-06-16T15:03:39.596Z', - machineName: 'examples:kitchenSink', + ], + type: 'fieldset', + hideLabel: true, + label: 'Field Set', + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + alwaysEnabled: false, + }, + { + type: 'button', + label: 'Submit', + key: 'submit', + disableOnInvalid: true, + input: true, + tableView: true, + alwaysEnabled: false, + labelWidth: 30, + labelMargin: 3, + widget: null, + clearOnRefresh: false, + }, + ], + revisions: '', + _vid: 0, + title: 'Kitchen Sink', + display: 'form', + access: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { + roles: ['5692b920d1028f01000407e4', '5692b920d1028f01000407e5', '5692b920d1028f01000407e6'], + type: 'read_all', + }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + submissionAccess: [ + { roles: ['5692b920d1028f01000407e6'], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { roles: [], type: 'read_all' }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + settings: {}, + properties: {}, + name: 'kitchenSink', + path: 'kitchensink', + project: '5692b91fd1028f01000407e3', + created: '2019-09-12T13:06:58.622Z', + modified: '2021-06-16T15:03:39.596Z', + machineName: 'examples:kitchenSink', }; export const otherForm = { - _id: '59121aaaed27e70083924f5b', - machineName: 'examples:e', - modified: '2021-06-08T21:04:52.339Z', - title: 'E', - display: 'form', - name: 'e', - path: 'e', - project: '5692b91fd1028f01000407e3', - created: '2017-05-09T19:38:18.503Z', - components: [ - { - key: 'content', - input: false, - html: '

You are on Page E!

\n', - type: 'content', - tableView: false, - label: 'Content', - }, - { - label: 'Total', - mask: false, - spellcheck: true, - disabled: true, - tableView: true, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - customDefaultValue: 'value = instance.root.data.score;', - calculateValue: { '+': [{ var: 'data.totalScore' }, { var: 'data.score' }] }, - key: 'total', - type: 'number', - inputType: 'number', - input: true, - }, - { - disabled: true, - type: 'number', - key: 'score', - label: 'Score', - inputType: 'number', - tableView: true, - input: true, - calculateValue: { - if: [ - { '==': [{ var: 'data.points' }, 'plus1'] }, - 1, - { '==': [{ var: 'data.points' }, 'plus2'] }, - 2, - { '==': [{ var: 'data.points' }, 'plus3'] }, - 3, - 0, - ], - }, - }, - { - input: true, - tableView: true, - label: 'Points', - key: 'points', - values: [ - { value: 'plus1', label: '+ 1' }, - { value: 'plus2', label: '+ 2' }, - { value: 'plus3', label: '+ 3' }, - { value: 'noChange', label: 'No Change' }, - ], - type: 'radio', - }, - { - input: true, - tableView: true, - label: 'Which page would you like to go to next?', - key: 'nextPage', - data: { - values: [ - { value: 'pageA', label: 'A' }, - { value: 'pageB', label: 'B' }, - { value: 'pageC', label: 'C' }, - { value: 'pageD', label: 'D' }, - { value: 'pageE', label: 'E' }, - { label: "I'm Done", value: 'done' }, - ], - }, - type: 'select', - lockKey: true, - }, - { input: true, label: 'Submit', tableView: false, key: 'submit', type: 'button' }, - ], - owner: '553dbfc08d22d5cb1a7024f2', - submissionAccess: [ - { roles: ['5692b920d1028f01000407e6'], type: 'create_all' }, - { roles: ['5692b920d1028f01000407e6'], type: 'read_all' }, - { roles: ['5692b920d1028f01000407e6'], type: 'update_all' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'create_own' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - access: [ - { roles: [], type: 'create_all' }, - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', - }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'create_own' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - tags: [], - type: 'form', - revisions: '', - _vid: 0, - settings: {}, + _id: '59121aaaed27e70083924f5b', + machineName: 'examples:e', + modified: '2021-06-08T21:04:52.339Z', + title: 'E', + display: 'form', + name: 'e', + path: 'e', + project: '5692b91fd1028f01000407e3', + created: '2017-05-09T19:38:18.503Z', + components: [ + { + key: 'content', + input: false, + html: '

You are on Page E!

\n', + type: 'content', + tableView: false, + label: 'Content', + }, + { + label: 'Total', + mask: false, + spellcheck: true, + disabled: true, + tableView: true, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + customDefaultValue: 'value = instance.root.data.score;', + calculateValue: { '+': [{ var: 'data.totalScore' }, { var: 'data.score' }] }, + key: 'total', + type: 'number', + inputType: 'number', + input: true, + }, + { + disabled: true, + type: 'number', + key: 'score', + label: 'Score', + inputType: 'number', + tableView: true, + input: true, + calculateValue: { + if: [ + { '==': [{ var: 'data.points' }, 'plus1'] }, + 1, + { '==': [{ var: 'data.points' }, 'plus2'] }, + 2, + { '==': [{ var: 'data.points' }, 'plus3'] }, + 3, + 0, + ], + }, + }, + { + input: true, + tableView: true, + label: 'Points', + key: 'points', + values: [ + { value: 'plus1', label: '+ 1' }, + { value: 'plus2', label: '+ 2' }, + { value: 'plus3', label: '+ 3' }, + { value: 'noChange', label: 'No Change' }, + ], + type: 'radio', + }, + { + input: true, + tableView: true, + label: 'Which page would you like to go to next?', + key: 'nextPage', + data: { + values: [ + { value: 'pageA', label: 'A' }, + { value: 'pageB', label: 'B' }, + { value: 'pageC', label: 'C' }, + { value: 'pageD', label: 'D' }, + { value: 'pageE', label: 'E' }, + { label: "I'm Done", value: 'done' }, + ], + }, + type: 'select', + lockKey: true, + }, + { input: true, label: 'Submit', tableView: false, key: 'submit', type: 'button' }, + ], + owner: '553dbfc08d22d5cb1a7024f2', + submissionAccess: [ + { roles: ['5692b920d1028f01000407e6'], type: 'create_all' }, + { roles: ['5692b920d1028f01000407e6'], type: 'read_all' }, + { roles: ['5692b920d1028f01000407e6'], type: 'update_all' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'create_own' }, + { roles: [], type: 'read_own' }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + access: [ + { roles: [], type: 'create_all' }, + { + roles: ['5692b920d1028f01000407e4', '5692b920d1028f01000407e5', '5692b920d1028f01000407e6'], + type: 'read_all', + }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'create_own' }, + { roles: [], type: 'read_own' }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + tags: [], + type: 'form', + revisions: '', + _vid: 0, + settings: {}, }; export const simpleNestedForm = { - display: 'form', - components: [ + display: 'form', + components: [ + { + collapsible: false, + key: 'panel', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - collapsible: false, - key: 'panel', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Data Grid', - reorder: false, - addAnotherPosition: 'bottom', - layoutFixed: false, - enableRowGroups: false, - initEmpty: false, - tableView: false, - defaultValue: [{}], - key: 'dataGrid', - type: 'datagrid', - input: true, - components: [ - { - label: 'Required Field', - applyMaskOn: 'change', - tableView: true, - validate: { - required: true, - }, - key: 'requiredField', - type: 'textfield', - input: true, - }, - { - label: 'Maximum Length', - applyMaskOn: 'change', - tableView: true, - validate: { - maxLength: 5, - }, - key: 'maximumLength', - type: 'textfield', - input: true, - }, - { - label: 'Numbers Only', - applyMaskOn: 'change', - tableView: true, - validate: { - pattern: '\\d', - }, - key: 'numbersOnly', - type: 'textfield', - input: true, - }, - ], - }, - { - label: 'Two Validations', - applyMaskOn: 'change', - tableView: true, - validate: { - pattern: '\\d', - minLength: 5, - }, - key: 'twoValidations', - type: 'textfield', - input: true, - }, - ], + label: 'Data Grid', + reorder: false, + addAnotherPosition: 'bottom', + layoutFixed: false, + enableRowGroups: false, + initEmpty: false, + tableView: false, + defaultValue: [{}], + key: 'dataGrid', + type: 'datagrid', + input: true, + components: [ + { + label: 'Required Field', + applyMaskOn: 'change', + tableView: true, + validate: { + required: true, + }, + key: 'requiredField', + type: 'textfield', + input: true, + }, + { + label: 'Maximum Length', + applyMaskOn: 'change', + tableView: true, + validate: { + maxLength: 5, + }, + key: 'maximumLength', + type: 'textfield', + input: true, + }, + { + label: 'Numbers Only', + applyMaskOn: 'change', + tableView: true, + validate: { + pattern: '\\d', + }, + key: 'numbersOnly', + type: 'textfield', + input: true, + }, + ], }, { - type: 'button', - label: 'Submit', - key: 'submit', - disableOnInvalid: true, - input: true, - tableView: false, + label: 'Two Validations', + applyMaskOn: 'change', + tableView: true, + validate: { + pattern: '\\d', + minLength: 5, + }, + key: 'twoValidations', + type: 'textfield', + input: true, }, - ], + ], + }, + { + type: 'button', + label: 'Submit', + key: 'submit', + disableOnInvalid: true, + input: true, + tableView: false, + }, + ], }; export const simpleCustomValidationForm = { - display: 'form', - components: [ - { - type: 'textfield', - key: 'customValidation', - validate: { - custom: 'valid = (input === "123") ? true : "Must be 123.";', - }, - input: true - } - ] -} + display: 'form', + components: [ + { + type: 'textfield', + key: 'customValidation', + validate: { + custom: 'valid = (input === "123") ? true : "Must be 123.";', + }, + input: true, + }, + ], +}; export const simpleJsonLogicValidationForm = { - display: 'form', - components: [ - { - type: 'textfield', - key: 'jsonLogic', - input: true, - validate: { - json: { - if: [ - { '===': [{ var: 'input' }, '123'] }, - true, - 'Must be 123.export ' - ] - } - } - } - ] -} + display: 'form', + components: [ + { + type: 'textfield', + key: 'jsonLogic', + input: true, + validate: { + json: { + if: [{ '===': [{ var: 'input' }, '123'] }, true, 'Must be 123.export '], + }, + }, + }, + ], +}; diff --git a/src/process/validation/__tests__/multiple.test.ts b/src/process/validation/__tests__/multiple.test.ts index 4c2c1b4e..b07ef82e 100644 --- a/src/process/validation/__tests__/multiple.test.ts +++ b/src/process/validation/__tests__/multiple.test.ts @@ -1,94 +1,92 @@ import { expect } from 'chai'; import { ValidationContext } from 'types'; -import { validationRules } from '..'; -import { rules, serverRules } from '../rules'; import { shouldValidate as shouldValidateRegexPattern } from '../rules/validateRegexPattern'; import { shouldValidate as shouldValidateRequired } from '../rules/validateRequired'; -const allRules = [...rules, ...serverRules]; - const textFieldComponent = { - type: 'textfield', - key: 'multiple_textfield', - label: 'Multiple Textfield', - input: true, - multiple: true, - validate: { - required: true, - maxLength: 10, - minLength: 5, - pattern: '^[0-9]+$', - } + type: 'textfield', + key: 'multiple_textfield', + label: 'Multiple Textfield', + input: true, + multiple: true, + validate: { + required: true, + maxLength: 10, + minLength: 5, + pattern: '^[0-9]+$', + }, }; const selectComponent = { - type: 'select', - key: 'multiple_select', - label: 'Multiple Select', - widget: 'choicesjs', - input: true, - multiple: true, - data: { - values: [ - { - label: 'A', - value: 'a', - }, - { - label: 'B', - value: 'b', - }, - { - label: 'C', - value: 'c', - }, - ], - }, - validate: { - required: true, - } + type: 'select', + key: 'multiple_select', + label: 'Multiple Select', + widget: 'choicesjs', + input: true, + multiple: true, + data: { + values: [ + { + label: 'A', + value: 'a', + }, + { + label: 'B', + value: 'b', + }, + { + label: 'C', + value: 'c', + }, + ], + }, + validate: { + required: true, + }, }; const context: ValidationContext = { - component: textFieldComponent, - value: [], - path: 'multiple_textfield', - data: {multiple_textfield: []}, - row: {multiple_textfield: []}, - scope: {errors: []}, + component: textFieldComponent, + value: [], + path: 'multiple_textfield', + data: { multiple_textfield: [] }, + row: { multiple_textfield: [] }, + scope: { errors: [] }, }; const contextWithSelectComponent: ValidationContext = { - component: selectComponent, - value: [], - path: 'multiple_select', - data: {multiple_select: []}, - row: {multiple_select: []}, - scope: {errors: []}, + component: selectComponent, + value: [], + path: 'multiple_select', + data: { multiple_select: [] }, + row: { multiple_select: [] }, + scope: { errors: [] }, }; -it('Validating required rule will work for multiple values component with no rows', async () => { +describe('Multiple values', function () { + it('Validating required rule will work for multiple values component with no rows', async function () { // TextField const shouldValidateRequiredTextField = shouldValidateRequired(context); expect(shouldValidateRequiredTextField).to.be.equal(true); // Select const shouldValidateRequiredSelect = shouldValidateRequired(contextWithSelectComponent); expect(shouldValidateRequiredSelect).to.be.equal(true); -}); + }); -it('Validate RegexPattern rule won\'t execute for multiple values component with no rows', async () => { + it("Validate RegexPattern rule won't execute for multiple values component with no rows", async function () { const shouldValidateRegexRule = shouldValidateRegexPattern(context); expect(shouldValidateRegexRule).to.be.equal(false); const contextWithValues = { - ...context, - value: 'a', - data: { - multiple_textfield: ['a'], - }, - row: { - multiple_textfield: ['a'], - }, + ...context, + value: 'a', + data: { + multiple_textfield: ['a'], + }, + row: { + multiple_textfield: ['a'], + }, }; const shouldValidateRegexRuleWithValues = shouldValidateRegexPattern(contextWithValues); expect(shouldValidateRegexRuleWithValues).to.be.equal(true); + }); }); diff --git a/src/process/validation/__tests__/util.test.ts b/src/process/validation/__tests__/util.test.ts index 3d7aaf8a..446975e0 100644 --- a/src/process/validation/__tests__/util.test.ts +++ b/src/process/validation/__tests__/util.test.ts @@ -3,147 +3,154 @@ import { expect } from 'chai'; import { interpolateErrors } from '../util'; import { validateProcess } from '../'; import { - simpleCustomValidationForm, - simpleForm, - simpleJsonLogicValidationForm, - simpleNestedForm + simpleCustomValidationForm, + simpleForm, + simpleJsonLogicValidationForm, + simpleNestedForm, } from './fixtures/forms'; import { ValidationScope, ProcessorType } from 'types'; -import { rules } from "../rules"; +import { rules } from '../rules'; import { eachComponentDataAsync } from 'utils/formUtil'; -describe('interpolateErrors', () => { - it('Interpolated validation errors should include the rule name mapping in the "validator" param for simple components', async () => { - const data = { - requiredField: '', - maximumWords: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - minimumWords: 'Hello', - email: 'brendanb', - url: 'htpigoogle', - inputMask: 'hello, world', - submit: false, - }; - const result: Map> = new Map(); - for (let component of simpleForm.components) { - const path = component.key; - const scope: ValidationScope = { errors: [] }; - await validateProcess({ - component, - scope, - data, - row: data, - path, - value: get(data, component.key), - processor: ProcessorType.Validate, - rules, - }); - result.set(path, interpolateErrors(scope.errors)); - } - expect(result.get('requiredField')).to.have.length(1); - expect(result.get('requiredField')![0].context.validator).to.equal('required'); - expect(result.get('maximumWords')).to.have.length(1); - expect(result.get('maximumWords')![0].context.validator).to.equal('maxWords'); - expect(result.get('minimumWords')).to.have.length(1); - expect(result.get('minimumWords')![0].context.validator).to.equal('minWords'); - expect(result.get('email')).to.have.length(1); - expect(result.get('email')![0].context.validator).to.equal('email'); - expect(result.get('url')).to.have.length(1); - expect(result.get('url')![0].context.validator).to.equal('url'); - expect(result.get('inputMask')).to.have.length(1); - expect(result.get('inputMask')![0].context.validator).to.equal('mask'); - }); +describe('interpolateErrors', function () { + it('Interpolated validation errors should include the rule name mapping in the "validator" param for simple components', async function () { + const data = { + requiredField: '', + maximumWords: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + minimumWords: 'Hello', + email: 'brendanb', + url: 'htpigoogle', + inputMask: 'hello, world', + submit: false, + }; + const result: Map> = new Map(); + for (const component of simpleForm.components) { + const path = component.key; + const scope: ValidationScope = { errors: [] }; + await validateProcess({ + component, + scope, + data, + row: data, + path, + value: get(data, component.key), + processor: ProcessorType.Validate, + rules, + }); + result.set(path, interpolateErrors(scope.errors)); + } + expect(result.get('requiredField')).to.have.length(1); + expect(result.get('requiredField')![0].context.validator).to.equal('required'); + expect(result.get('maximumWords')).to.have.length(1); + expect(result.get('maximumWords')![0].context.validator).to.equal('maxWords'); + expect(result.get('minimumWords')).to.have.length(1); + expect(result.get('minimumWords')![0].context.validator).to.equal('minWords'); + expect(result.get('email')).to.have.length(1); + expect(result.get('email')![0].context.validator).to.equal('email'); + expect(result.get('url')).to.have.length(1); + expect(result.get('url')![0].context.validator).to.equal('url'); + expect(result.get('inputMask')).to.have.length(1); + expect(result.get('inputMask')![0].context.validator).to.equal('mask'); + }); - it('Interpolated validation errors should include the rule name mapping in the "validator" param for nested components', async () => { - const data = { - dataGrid: [ - { - requiredField: '', - maximumLength: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - numbersOnly: 'abc', - submit: false, - }, - { - requiredField: '', - maximumLength: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - numbersOnly: 'abc', - submit: false, - },, - ] - }; - const result: Map> = new Map(); - await eachComponentDataAsync(simpleNestedForm.components, data, async (component, data, row, path) => { - const scope: ValidationScope = { errors: [] }; - await validateProcess({ - component, - scope, - data, - row: data, - path, - value: get(data, path), - processor: ProcessorType.Validate, - rules, - }); - result.set(path, interpolateErrors(scope.errors)); + it('Interpolated validation errors should include the rule name mapping in the "validator" param for nested components', async function () { + const data = { + dataGrid: [ + { + requiredField: '', + maximumLength: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + numbersOnly: 'abc', + submit: false, + }, + { + requiredField: '', + maximumLength: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + numbersOnly: 'abc', + submit: false, + }, + ], + }; + const result: Map> = new Map(); + await eachComponentDataAsync( + simpleNestedForm.components, + data, + async (component, data, row, path) => { + const scope: ValidationScope = { errors: [] }; + await validateProcess({ + component, + scope, + data, + row: data, + path, + value: get(data, path), + processor: ProcessorType.Validate, + rules, }); - expect(result.get('dataGrid[0].requiredField')).to.have.length(1); - expect(result.get('dataGrid[0].requiredField')![0].context.validator).to.equal('required'); - expect(result.get('dataGrid[1].requiredField')).to.have.length(1); - expect(result.get('dataGrid[1].requiredField')![0].context.validator).to.equal('required'); - expect(result.get('dataGrid[0].maximumLength')).to.have.length(1); - expect(result.get('dataGrid[0].maximumLength')![0].context.validator).to.equal('maxLength'); - expect(result.get('dataGrid[1].maximumLength')).to.have.length(1); - expect(result.get('dataGrid[1].maximumLength')![0].context.validator).to.equal('maxLength'); - expect(result.get('dataGrid[0].numbersOnly')).to.have.length(1); - expect(result.get('dataGrid[0].numbersOnly')![0].context.validator).to.equal('pattern'); - }); + result.set(path, interpolateErrors(scope.errors)); + }, + ); + expect(result.get('dataGrid[0].requiredField')).to.have.length(1); + expect(result.get('dataGrid[0].requiredField')![0].context.validator).to.equal('required'); + expect(result.get('dataGrid[1].requiredField')).to.have.length(1); + expect(result.get('dataGrid[1].requiredField')![0].context.validator).to.equal('required'); + expect(result.get('dataGrid[0].maximumLength')).to.have.length(1); + expect(result.get('dataGrid[0].maximumLength')![0].context.validator).to.equal('maxLength'); + expect(result.get('dataGrid[1].maximumLength')).to.have.length(1); + expect(result.get('dataGrid[1].maximumLength')![0].context.validator).to.equal('maxLength'); + expect(result.get('dataGrid[0].numbersOnly')).to.have.length(1); + expect(result.get('dataGrid[0].numbersOnly')![0].context.validator).to.equal('pattern'); + }); - it('Interpolated validation errors should include the rule name mapping in the "validator" param for components with custom validation', async () => { - const data = { - customValidation: 'abc', - submit: false, - }; - const result: Map> = new Map(); - for (let component of simpleCustomValidationForm.components) { - const path = component.key; - const scope: ValidationScope = { errors: [] }; - await validateProcess({ - component, - scope, - data, - row: data, - path, - value: get(data, component.key), - processor: ProcessorType.Validate, - rules, - }); - result.set(path, interpolateErrors(scope.errors)); - } - expect(result.get('customValidation')).to.have.length(1); - expect(result.get('customValidation')![0].context.validator).to.equal('custom'); - }); + it('Interpolated validation errors should include the rule name mapping in the "validator" param for components with custom validation', async function () { + const data = { + customValidation: 'abc', + submit: false, + }; + const result: Map> = new Map(); + for (const component of simpleCustomValidationForm.components) { + const path = component.key; + const scope: ValidationScope = { errors: [] }; + await validateProcess({ + component, + scope, + data, + row: data, + path, + value: get(data, component.key), + processor: ProcessorType.Validate, + rules, + }); + result.set(path, interpolateErrors(scope.errors)); + } + expect(result.get('customValidation')).to.have.length(1); + expect(result.get('customValidation')![0].context.validator).to.equal('custom'); + }); - it('Interpolated validation errors should include the rule name mapping in the "validator" param for components with json logic validation', async () => { - const data = { - jsonLogic: 'abc', - submit: false, - }; - const result: Map> = new Map(); - for (let component of simpleJsonLogicValidationForm.components) { - const path = component.key; - const scope: ValidationScope = { errors: [] }; - await validateProcess({ - component, - scope, - data, - row: data, - path, - value: get(data, component.key), - processor: ProcessorType.Validate, - rules, - }); - result.set(path, interpolateErrors(scope.errors)); - } - expect(result.get('jsonLogic')).to.have.length(1); - expect(result.get('jsonLogic')![0].context.validator).to.equal('json'); - }); -}) + it('Interpolated validation errors should include the rule name mapping in the "validator" param for components with json logic validation', async function () { + const data = { + jsonLogic: 'abc', + submit: false, + }; + const result: Map> = new Map(); + for (const component of simpleJsonLogicValidationForm.components) { + const path = component.key; + const scope: ValidationScope = { errors: [] }; + await validateProcess({ + component, + scope, + data, + row: data, + path, + value: get(data, component.key), + processor: ProcessorType.Validate, + rules, + }); + result.set(path, interpolateErrors(scope.errors)); + } + expect(result.get('jsonLogic')).to.have.length(1); + expect(result.get('jsonLogic')![0].context.validator).to.equal('json'); + }); +}); diff --git a/src/process/validation/i18n/en.ts b/src/process/validation/i18n/en.ts index 53a78a3b..9fb89931 100644 --- a/src/process/validation/i18n/en.ts +++ b/src/process/validation/i18n/en.ts @@ -1,40 +1,40 @@ export const EN_ERRORS = { - unsavedRowsError: 'Please save all rows before proceeding.', - invalidRowsError: 'Please correct invalid rows before proceeding.', - invalidRowError: 'Invalid row. Please correct it or delete.', - invalidOption: '{{field}} is an invalid value.', - invalidDay: '{{field}} is not a valid day.', - required: '{{field}} is required', - unique: '{{field}} must be unique', - array: '{{field}} must be an array', - array_nonempty: '{{field}} must be a non-empty array', // eslint-disable-line camelcase - nonarray: '{{field}} must not be an array', - select: '{{field}} contains an invalid selection', - pattern: '{{field}} does not match the pattern {{pattern}}', - minLength: '{{field}} must have at least {{length}} characters.', - maxLength: '{{field}} must have no more than {{length}} characters.', - minWords: '{{field}} must have at least {{length}} words.', - maxWords: '{{field}} must have no more than {{length}} words.', - min: '{{field}} cannot be less than {{min}}.', - max: '{{field}} cannot be greater than {{max}}.', - maxDate: '{{field}} should not contain date after {{- maxDate}}', - minDate: '{{field}} should not contain date before {{- minDate}}', - maxYear: '{{field}} should not contain year greater than {{maxYear}}', - minSelectedCount: 'You must select at least {{minCount}} items', - maxSelectedCount: 'You may only select up to {{maxCount}} items', - minYear: '{{field}} should not contain year less than {{minYear}}', - invalid_email: '{{field}} must be a valid email.', // eslint-disable-line camelcase - invalid_url: '{{field}} must be a valid url.', // eslint-disable-line camelcase - invalid_regex: '{{field}} does not match the pattern {{regex}}.', // eslint-disable-line camelcase - invalid_date: '{{field}} is not a valid date.', // eslint-disable-line camelcase - invalid_day: '{{field}} is not a valid day.', // eslint-disable-line camelcase - invalidValueProperty: 'Invalid Value Property', - mask: '{{field}} does not match the mask.', - valueIsNotAvailable: '{{ field }} is an invalid value.', - time: '{{field}} is not a valid time.', - invalidDate: '{{field}} is not a valid date', - number: '{{field}} is not a valid number.', - requiredDayField: '{{ field }} is required', - requiredMonthField: '{{ field }} is required', - requiredYearField: '{{ field }} is required' + unsavedRowsError: 'Please save all rows before proceeding.', + invalidRowsError: 'Please correct invalid rows before proceeding.', + invalidRowError: 'Invalid row. Please correct it or delete.', + invalidOption: '{{field}} is an invalid value.', + invalidDay: '{{field}} is not a valid day.', + required: '{{field}} is required', + unique: '{{field}} must be unique', + array: '{{field}} must be an array', + array_nonempty: '{{field}} must be a non-empty array', + nonarray: '{{field}} must not be an array', + select: '{{field}} contains an invalid selection', + pattern: '{{field}} does not match the pattern {{pattern}}', + minLength: '{{field}} must have at least {{length}} characters.', + maxLength: '{{field}} must have no more than {{length}} characters.', + minWords: '{{field}} must have at least {{length}} words.', + maxWords: '{{field}} must have no more than {{length}} words.', + min: '{{field}} cannot be less than {{min}}.', + max: '{{field}} cannot be greater than {{max}}.', + maxDate: '{{field}} should not contain date after {{- maxDate}}', + minDate: '{{field}} should not contain date before {{- minDate}}', + maxYear: '{{field}} should not contain year greater than {{maxYear}}', + minSelectedCount: 'You must select at least {{minCount}} items', + maxSelectedCount: 'You may only select up to {{maxCount}} items', + minYear: '{{field}} should not contain year less than {{minYear}}', + invalid_email: '{{field}} must be a valid email.', + invalid_url: '{{field}} must be a valid url.', + invalid_regex: '{{field}} does not match the pattern {{regex}}.', + invalid_date: '{{field}} is not a valid date.', + invalid_day: '{{field}} is not a valid day.', + invalidValueProperty: 'Invalid Value Property', + mask: '{{field}} does not match the mask.', + valueIsNotAvailable: '{{ field }} is an invalid value.', + time: '{{field}} is not a valid time.', + invalidDate: '{{field}} is not a valid date', + number: '{{field}} is not a valid number.', + requiredDayField: '{{ field }} is required', + requiredMonthField: '{{ field }} is required', + requiredYearField: '{{ field }} is required', }; diff --git a/src/process/validation/i18n/index.ts b/src/process/validation/i18n/index.ts index 7a09c0a4..60e3577c 100644 --- a/src/process/validation/i18n/index.ts +++ b/src/process/validation/i18n/index.ts @@ -1,4 +1,4 @@ -import { EN_ERRORS } from "./en" +import { EN_ERRORS } from './en'; export const VALIDATION_ERRORS: Record> = { - en: EN_ERRORS -}; \ No newline at end of file + en: EN_ERRORS, +}; diff --git a/src/process/validation/index.ts b/src/process/validation/index.ts index 7469479b..daacee41 100644 --- a/src/process/validation/index.ts +++ b/src/process/validation/index.ts @@ -1,354 +1,412 @@ -import { ConditionsScope, ProcessorFn, ProcessorFnSync, ProcessorInfo, ValidationContext, ValidationProcessorFn, ValidationProcessorFnSync, ValidationRuleInfo, ValidationScope, SkipValidationFn, ConditionsContext } from "types"; -import { evaluationRules, rules, serverRules } from "./rules"; -import find from "lodash/find"; -import get from "lodash/get"; -import pick from "lodash/pick"; -import { getComponentAbsolutePath, getComponentPath } from "utils/formUtil"; -import { getErrorMessage } from "utils/error"; -import { FieldError } from "error"; -import { ConditionallyHidden, isConditionallyHidden, isCustomConditionallyHidden, isSimpleConditionallyHidden } from "processes/conditions"; +import { + ConditionsScope, + ProcessorFn, + ProcessorFnSync, + ProcessorInfo, + ValidationContext, + ValidationProcessorFn, + ValidationProcessorFnSync, + ValidationRuleInfo, + ValidationScope, + SkipValidationFn, + ConditionsContext, +} from 'types'; +import { evaluationRules, rules, serverRules } from './rules'; +import find from 'lodash/find'; +import get from 'lodash/get'; +import pick from 'lodash/pick'; +import { getComponentAbsolutePath, getComponentPath } from 'utils/formUtil'; +import { getErrorMessage } from 'utils/error'; +import { FieldError } from 'error'; +import { + ConditionallyHidden, + isConditionallyHidden, + isCustomConditionallyHidden, + isSimpleConditionallyHidden, +} from 'processes/conditions'; // Cleans up validation errors to remove unnessesary parts // and make them transferable to ivm. const cleanupValidationError = (error: any) => ({ - ...error, - context: pick(error.context, - [ - 'component', - 'path', - 'index', - 'value', - 'field', - 'hasLabel', - 'processor', - 'setting', - 'pattern', - 'length', - 'min', - 'max', - 'maxDate', - 'minDate', - 'maxYear', - 'minYear', - 'minCount', - 'maxCount', - 'regex' - ] - ), + ...error, + context: pick(error.context, [ + 'component', + 'path', + 'index', + 'value', + 'field', + 'hasLabel', + 'processor', + 'setting', + 'pattern', + 'length', + 'min', + 'max', + 'maxDate', + 'minDate', + 'maxYear', + 'minYear', + 'minCount', + 'maxCount', + 'regex', + ]), }); export function validationRules( - context: ValidationContext, - rules: ValidationRuleInfo[], - skipValidation?: SkipValidationFn + context: ValidationContext, + rules: ValidationRuleInfo[], + skipValidation?: SkipValidationFn, ): ValidationRuleInfo[] { - if (skipValidation && skipValidation(context)) { - return []; + if (skipValidation && skipValidation(context)) { + return []; + } + const validationRules: ValidationRuleInfo[] = []; + return rules.reduce((acc, rule: ValidationRuleInfo) => { + if (rule.shouldProcess && rule.shouldProcess(context)) { + acc.push(rule); } - const validationRules: ValidationRuleInfo[] = []; - return rules.reduce((acc, rule: ValidationRuleInfo) => { - if (rule.shouldProcess && rule.shouldProcess(context)) { - acc.push(rule); - } - return acc; - }, validationRules); + return acc; + }, validationRules); } export function isInputComponent(context: ValidationContext): boolean { - const { component } = context; - return !component.hasOwnProperty('input') || component.input; + const { component } = context; + return !component.hasOwnProperty('input') || component.input; } export function isValueHidden(context: ValidationContext): boolean { - const { component, config } = context; - if (component.protected) { - return false; - } - if ( - (component.hasOwnProperty('persistent') && !component.persistent) || - (component.persistent === 'client-only') - ) { - return true; - } + const { component } = context; + if (component.protected) { return false; + } + if ( + (component.hasOwnProperty('persistent') && !component.persistent) || + component.persistent === 'client-only' + ) { + return true; + } + return false; } -export function isForcedHidden(context: ValidationContext, isConditionallyHidden: ConditionallyHidden): boolean { - const { component } = context; - if (isConditionallyHidden(context as ConditionsContext)) { - return true; - } - if (component.hasOwnProperty('hidden')) { - return !!component.hidden; - } - return false; +export function isForcedHidden( + context: ValidationContext, + isConditionallyHidden: ConditionallyHidden, +): boolean { + const { component } = context; + if (isConditionallyHidden(context as ConditionsContext)) { + return true; + } + if (component.hasOwnProperty('hidden')) { + return !!component.hidden; + } + return false; } -export const _shouldSkipValidation = (context: ValidationContext, isConditionallyHidden: ConditionallyHidden) => { - const { component, scope, path } = context; +export const _shouldSkipValidation = ( + context: ValidationContext, + isConditionallyHidden: ConditionallyHidden, +) => { + const { component, scope, path } = context; - if ( - (scope as ConditionsScope)?.conditionals && - (find((scope as ConditionsScope).conditionals, { - path: getComponentPath(component, path), - conditionallyHidden: true - }) || component.ephemeralState?.conditionallyHidden === true) - ) { - return true; - } - const { validateWhenHidden = false } = component || {}; - const rules = [ - // Skip validation if component is readOnly - // () => this.options.readOnly, - // Do not check validations if component is not an input component. - () => !isInputComponent(context), - // Check to see if we are editing and if so, check component persistence. - () => isValueHidden(context), - // Force valid if component is hidden. - () => isForcedHidden(context, isConditionallyHidden) && !validateWhenHidden, - ]; + if ( + (scope as ConditionsScope)?.conditionals && + (find((scope as ConditionsScope).conditionals, { + path: getComponentPath(component, path), + conditionallyHidden: true, + }) || + component.ephemeralState?.conditionallyHidden === true) + ) { + return true; + } + const { validateWhenHidden = false } = component || {}; + const rules = [ + // Skip validation if component is readOnly + // () => this.options.readOnly, + // Do not check validations if component is not an input component. + () => !isInputComponent(context), + // Check to see if we are editing and if so, check component persistence. + () => isValueHidden(context), + // Force valid if component is hidden. + () => isForcedHidden(context, isConditionallyHidden) && !validateWhenHidden, + ]; - return rules.some(pred => pred());; + return rules.some((pred) => pred()); }; export const shouldSkipValidationCustom: SkipValidationFn = (context: ValidationContext) => { - return _shouldSkipValidation(context, isCustomConditionallyHidden); + return _shouldSkipValidation(context, isCustomConditionallyHidden); }; export const shouldSkipValidationSimple: SkipValidationFn = (context: ValidationContext) => { - return _shouldSkipValidation(context, isSimpleConditionallyHidden); + return _shouldSkipValidation(context, isSimpleConditionallyHidden); }; export const shouldSkipValidation: SkipValidationFn = (context: ValidationContext) => { - return _shouldSkipValidation(context, isConditionallyHidden); + return _shouldSkipValidation(context, isConditionallyHidden); }; export function shouldValidateAll(context: ValidationContext): boolean { - return validationRules(context, rules, shouldSkipValidation).length > 0; + return validationRules(context, rules, shouldSkipValidation).length > 0; } export function shouldValidateCustom(context: ValidationContext): boolean { - const { component } = context; - if (component.customConditional) { - return true; - } - return !shouldSkipValidationCustom(context); + const { component } = context; + if (component.customConditional) { + return true; + } + return !shouldSkipValidationCustom(context); } export function shouldValidateServer(context: ValidationContext): boolean { - const { component } = context; - if (component.customConditional) { - return false; - } - if (shouldSkipValidationSimple(context)) { - return false; - } - return shouldValidateAll(context); + const { component } = context; + if (component.customConditional) { + return false; + } + if (shouldSkipValidationSimple(context)) { + return false; + } + return shouldValidateAll(context); } function handleError(error: FieldError | null, context: ValidationContext) { - const { scope, component } = context; - const absolutePath = getComponentAbsolutePath(component); - if (error) { - const cleanedError = cleanupValidationError(error); - cleanedError.context.path = absolutePath; - if (!find(scope.errors, { errorKeyOrMessage: cleanedError.errorKeyOrMessage, context: { - path: absolutePath - }})) { - if (!scope.validated) scope.validated = []; - if (!scope.errors) scope.errors = []; - scope.errors.push(cleanedError); - scope.validated.push({ path: absolutePath, error: cleanedError }); - } + const { scope, component } = context; + const absolutePath = getComponentAbsolutePath(component); + if (error) { + const cleanedError = cleanupValidationError(error); + cleanedError.context.path = absolutePath; + if ( + !find(scope.errors, { + errorKeyOrMessage: cleanedError.errorKeyOrMessage, + context: { + path: absolutePath, + }, + }) + ) { + if (!scope.validated) scope.validated = []; + if (!scope.errors) scope.errors = []; + scope.errors.push(cleanedError); + scope.validated.push({ path: absolutePath, error: cleanedError }); } + } } export const validateProcess: ValidationProcessorFn = async (context) => { - const { component, data, row, path, instance, scope, rules, skipValidation } = context; - let { value } = context; - if (!scope.validated) scope.validated = []; - if (!scope.errors) scope.errors = []; - if (!rules || !rules.length) { + const { component, data, row, path, instance, scope, rules, skipValidation } = context; + let { value } = context; + if (!scope.validated) scope.validated = []; + if (!scope.errors) scope.errors = []; + if (!rules || !rules.length) { + return; + } + if (component.multiple && Array.isArray(value) && value.length > 0) { + const fullValueRules = rules.filter((rule) => rule.fullValue); + const otherRules = rules.filter((rule) => !rule.fullValue); + for (let i = 0; i < value.length; i++) { + const amendedPath = `${path}[${i}]`; + let amendedValue = get(data, amendedPath); + if (instance?.shouldSkipValidation(data)) { return; - } - if (component.multiple && Array.isArray(value) && value.length > 0) { - const fullValueRules = rules.filter(rule => rule.fullValue); - const otherRules = rules.filter(rule => !rule.fullValue); - for (let i = 0; i < value.length; i++) { - const amendedPath = `${path}[${i}]`; - let amendedValue = get(data, amendedPath); - if (instance?.shouldSkipValidation(data)) { - return; - } - const rulesToExecute: ValidationRuleInfo[] = validationRules(context, otherRules, skipValidation); - if (!rulesToExecute.length) { - continue; - } - if (component.truncateMultipleSpaces && amendedValue && typeof amendedValue === 'string') { - amendedValue = amendedValue.trim().replace(/\s{2,}/g, ' '); - } - for (const rule of rulesToExecute) { - if (rule && rule.process) { - handleError(await rule.process({ - ...context, - value: amendedValue, - index: i, - path: amendedPath - }), context); - } - } + } + const rulesToExecute: ValidationRuleInfo[] = validationRules( + context, + otherRules, + skipValidation, + ); + if (!rulesToExecute.length) { + continue; + } + if (component.truncateMultipleSpaces && amendedValue && typeof amendedValue === 'string') { + amendedValue = amendedValue.trim().replace(/\s{2,}/g, ' '); + } + for (const rule of rulesToExecute) { + if (rule && rule.process) { + handleError( + await rule.process({ + ...context, + value: amendedValue, + index: i, + path: amendedPath, + }), + context, + ); } - for (const rule of fullValueRules) { - if (rule && rule.process) { - handleError(await rule.process({ - ...context, - value - }), context); - } - } - return; + } } - if (instance?.shouldSkipValidation(data, row)) { - return; - } - const rulesToExecute: ValidationRuleInfo[] = validationRules(context, rules, skipValidation); - if (!rulesToExecute.length) { - return; - } - if (component.truncateMultipleSpaces && value && typeof value === 'string') { - value = value.trim().replace(/\s{2,}/g, ' '); - } - for (const rule of rulesToExecute) { - try { - if (rule && rule.process) { - handleError(await rule.process({ ...context, value }), context); - } - } - catch (err) { - console.error("Validator error:", getErrorMessage(err)); - } + for (const rule of fullValueRules) { + if (rule && rule.process) { + handleError( + await rule.process({ + ...context, + value, + }), + context, + ); + } } return; + } + if (instance?.shouldSkipValidation(data, row)) { + return; + } + const rulesToExecute: ValidationRuleInfo[] = validationRules(context, rules, skipValidation); + if (!rulesToExecute.length) { + return; + } + if (component.truncateMultipleSpaces && value && typeof value === 'string') { + value = value.trim().replace(/\s{2,}/g, ' '); + } + for (const rule of rulesToExecute) { + try { + if (rule && rule.process) { + handleError(await rule.process({ ...context, value }), context); + } + } catch (err) { + console.error('Validator error:', getErrorMessage(err)); + } + } + return; }; export const validateProcessSync: ValidationProcessorFnSync = (context) => { - const { component, data, row, path, instance, scope, rules, skipValidation } = context; - let { value } = context; - if (!scope.validated) scope.validated = []; - if (!scope.errors) scope.errors = []; - if (!rules || !rules.length) { + const { component, data, row, path, instance, scope, rules, skipValidation } = context; + let { value } = context; + if (!scope.validated) scope.validated = []; + if (!scope.errors) scope.errors = []; + if (!rules || !rules.length) { + return; + } + if (component.multiple && Array.isArray(value) && value.length > 0) { + const fullValueRules = rules.filter((rule) => rule.fullValue); + const otherRules = rules.filter((rule) => !rule.fullValue); + for (let i = 0; i < value.length; i++) { + const amendedPath = `${path}[${i}]`; + let amendedValue = get(data, amendedPath); + if (instance?.shouldSkipValidation(data)) { return; - } - if (component.multiple && Array.isArray(value) && value.length > 0) { - const fullValueRules = rules.filter(rule => rule.fullValue); - const otherRules = rules.filter(rule => !rule.fullValue); - for (let i = 0; i < value.length; i++) { - const amendedPath = `${path}[${i}]`; - let amendedValue = get(data, amendedPath); - if (instance?.shouldSkipValidation(data)) { - return; - } - const rulesToExecute: ValidationRuleInfo[] = validationRules(context, otherRules, skipValidation); - if (!rulesToExecute.length) { - continue; - } - if (component.truncateMultipleSpaces && amendedValue && typeof amendedValue === 'string') { - amendedValue = amendedValue.trim().replace(/\s{2,}/g, ' '); - } - for (const rule of rulesToExecute) { - if (rule && rule.processSync) { - handleError(rule.processSync({ ...context, value: amendedValue, index: i, path: amendedPath }), context); - } - } - } - for (const rule of fullValueRules) { - if (rule && rule.processSync) { - handleError(rule.processSync({ - ...context, - value - }), context); - } + } + const rulesToExecute: ValidationRuleInfo[] = validationRules( + context, + otherRules, + skipValidation, + ); + if (!rulesToExecute.length) { + continue; + } + if (component.truncateMultipleSpaces && amendedValue && typeof amendedValue === 'string') { + amendedValue = amendedValue.trim().replace(/\s{2,}/g, ' '); + } + for (const rule of rulesToExecute) { + if (rule && rule.processSync) { + handleError( + rule.processSync({ + ...context, + value: amendedValue, + index: i, + path: amendedPath, + }), + context, + ); } - return; - } - if (instance?.shouldSkipValidation(data, row)) { - return; + } } - const rulesToExecute: ValidationRuleInfo[] = validationRules(context, rules, skipValidation); - if (!rulesToExecute.length) { - return; - } - if (component.truncateMultipleSpaces && value && typeof value === 'string') { - value = value.trim().replace(/\s{2,}/g, ' '); - } - for (const rule of rulesToExecute) { - try { - if (rule && rule.processSync) { - handleError(rule.processSync({ ...context, value }), context); - } - } - catch (err) { - console.error("Validator error:", getErrorMessage(err)); - } + for (const rule of fullValueRules) { + if (rule && rule.processSync) { + handleError( + rule.processSync({ + ...context, + value, + }), + context, + ); + } } return; + } + if (instance?.shouldSkipValidation(data, row)) { + return; + } + const rulesToExecute: ValidationRuleInfo[] = validationRules(context, rules, skipValidation); + if (!rulesToExecute.length) { + return; + } + if (component.truncateMultipleSpaces && value && typeof value === 'string') { + value = value.trim().replace(/\s{2,}/g, ' '); + } + for (const rule of rulesToExecute) { + try { + if (rule && rule.processSync) { + handleError(rule.processSync({ ...context, value }), context); + } + } catch (err) { + console.error('Validator error:', getErrorMessage(err)); + } + } + return; }; export const validateCustomProcess: ValidationProcessorFn = async (context) => { - context.rules = context.rules || evaluationRules; - context.skipValidation = shouldSkipValidationCustom; - return validateProcess(context); + context.rules = context.rules || evaluationRules; + context.skipValidation = shouldSkipValidationCustom; + return validateProcess(context); }; -export const validateCustomProcessSync: ProcessorFnSync = (context: ValidationContext) => { - context.rules = context.rules || evaluationRules; - context.skipValidation = shouldSkipValidationCustom; - return validateProcessSync(context); +export const validateCustomProcessSync: ProcessorFnSync = ( + context: ValidationContext, +) => { + context.rules = context.rules || evaluationRules; + context.skipValidation = shouldSkipValidationCustom; + return validateProcessSync(context); }; export const validateServerProcess: ValidationProcessorFn = async (context) => { - context.rules = context.rules || serverRules; - context.skipValidation = shouldSkipValidationSimple; - return validateProcess(context); + context.rules = context.rules || serverRules; + context.skipValidation = shouldSkipValidationSimple; + return validateProcess(context); }; -export const validateServerProcessSync: ProcessorFnSync = (context: ValidationContext) => { - context.rules = context.rules || serverRules; - context.skipValidation = shouldSkipValidationSimple; - return validateProcessSync(context); +export const validateServerProcessSync: ProcessorFnSync = ( + context: ValidationContext, +) => { + context.rules = context.rules || serverRules; + context.skipValidation = shouldSkipValidationSimple; + return validateProcessSync(context); }; -export const validateAllProcess: ProcessorFn = async (context: ValidationContext) => { - context.rules = context.rules || rules; - context.skipValidation = shouldSkipValidation; - return validateProcess(context); +export const validateAllProcess: ProcessorFn = async ( + context: ValidationContext, +) => { + context.rules = context.rules || rules; + context.skipValidation = shouldSkipValidation; + return validateProcess(context); }; -export const validateAllProcessSync: ProcessorFnSync = (context: ValidationContext) => { - context.rules = context.rules || rules; - context.skipValidation = shouldSkipValidation; - return validateProcessSync(context); +export const validateAllProcessSync: ProcessorFnSync = ( + context: ValidationContext, +) => { + context.rules = context.rules || rules; + context.skipValidation = shouldSkipValidation; + return validateProcessSync(context); }; export const validateCustomProcessInfo: ProcessorInfo = { - name: 'validateCustom', - process: validateCustomProcess, - processSync: validateCustomProcessSync, - shouldProcess: shouldValidateCustom, + name: 'validateCustom', + process: validateCustomProcess, + processSync: validateCustomProcessSync, + shouldProcess: shouldValidateCustom, }; export const validateServerProcessInfo: ProcessorInfo = { - name: 'validateServer', - process: validateServerProcess, - processSync: validateServerProcessSync, - shouldProcess: shouldValidateServer, + name: 'validateServer', + process: validateServerProcess, + processSync: validateServerProcessSync, + shouldProcess: shouldValidateServer, }; export const validateProcessInfo: ProcessorInfo = { - name: 'validate', - process: validateAllProcess, - processSync: validateAllProcessSync, - shouldProcess: shouldValidateAll, + name: 'validate', + process: validateAllProcess, + processSync: validateAllProcessSync, + shouldProcess: shouldValidateAll, }; export * from './util'; diff --git a/src/process/validation/rules/__tests__/fixtures/components.d.ts b/src/process/validation/rules/__tests__/fixtures/components.d.ts deleted file mode 100644 index 4368277b..00000000 --- a/src/process/validation/rules/__tests__/fixtures/components.d.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { - DateTimeComponent, - DayComponent, - NumberComponent, - RadioComponent, - SelectBoxesComponent, - SelectComponentOptions, - TextFieldComponent, -} from '../../src/types/Component'; -export declare const simpleTextField: TextFieldComponent; -export declare const simpleDateTimeField: DateTimeComponent; -export declare const simpleDayField: DayComponent; -export declare const calendarTextField: TextFieldComponent; -export declare const simpleEmailField: { - label: string; - tableView: boolean; - key: string; - type: string; - input: boolean; -}; -export declare const simpleSelectBoxes: SelectBoxesComponent; -export declare const simpleNumberField: NumberComponent; -export declare const simpleUrlField: { - label: string; - tableView: boolean; - key: string; - type: string; - input: boolean; -}; -export declare const simpleSelectOptions: SelectComponentOptions; -export declare const simpleRadioField: RadioComponent; diff --git a/src/process/validation/rules/__tests__/fixtures/components.js b/src/process/validation/rules/__tests__/fixtures/components.js deleted file mode 100644 index 74c21d68..00000000 --- a/src/process/validation/rules/__tests__/fixtures/components.js +++ /dev/null @@ -1,216 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.requiredNonInputField = exports.conditionallyHiddenRequiredHiddenField = exports.hiddenRequiredField = exports.simpleRadioField = exports.simpleSelectOptions = exports.simpleUrlField = exports.simpleNumberField = exports.simpleSelectBoxes = exports.simpleEmailField = exports.calendarTextField = exports.simpleDayField = exports.simpleDateTimeField = exports.simpleTextField = void 0; -exports.simpleTextField = { - type: 'textField', - label: 'Simple Text Field', - input: true, - tableView: true, - key: 'component', -}; -exports.simpleDateTimeField = { - tableView: false, - label: 'Simple Date/Time', - datePicker: { - disableWeekends: false, - disableWeekdays: false, - }, - enableMinDateInput: false, - enableMaxDateInput: false, - enableDate: true, - key: 'component', - type: 'datetime', - input: true, - widget: { - type: 'calendar', - displayInTimezone: 'viewer', - locale: 'en', - useLocaleSettings: false, - allowInput: true, - mode: 'single', - enableTime: true, - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - hourIncrement: 1, - minuteIncrement: 1, - time_24hr: false, - disableWeekends: false, - disableWeekdays: false, - }, -}; -exports.simpleDayField = { - label: 'Simple Day', - hideInputLabels: false, - inputsLabelPosition: 'top', - useLocaleSettings: false, - tableView: false, - fields: { - day: { - hide: false, - }, - month: { - hide: false, - }, - year: { - hide: false, - }, - }, - key: 'component', - type: 'day', - input: true, - defaultValue: '00/00/0000', -}; -exports.calendarTextField = { - label: 'Text Field', - widget: { - type: 'calendar', - altInput: true, - allowInput: true, - clickOpens: true, - // enableDate: true, - enableTime: true, - mode: 'single', - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-ddTHH:mm:ssZ', - useLocaleSettings: false, - hourIncrement: 1, - minuteIncrement: 5, - time_24hr: false, - saveAs: 'text', - displayInTimezone: 'viewer', - locale: 'en', - }, - tableView: true, - key: 'component', - type: 'textfield', - input: true, -}; -exports.simpleEmailField = { - label: 'Email', - tableView: true, - key: 'component', - type: 'email', - input: true, -}; -exports.simpleSelectBoxes = { - label: 'Select Boxes', - optionsLabelPosition: 'right', - tableView: false, - values: [ - { - label: 'foo', - value: 'foo', - }, - { - label: 'bar', - value: 'bar', - }, - { - label: 'baz', - value: 'baz', - }, - { - label: 'biz', - value: 'biz', - }, - ], - validate: { - maxSelectedCount: 3, - }, - key: 'component', - type: 'selectboxes', - input: true, - inputType: 'checkbox', -}; -exports.simpleNumberField = { - label: 'Number', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - truncateMultipleSpaces: false, - key: 'component', - type: 'number', - input: true, -}; -exports.simpleUrlField = { - label: 'Url', - tableView: true, - key: 'component', - type: 'url', - input: true, -}; -exports.simpleSelectOptions = { - label: 'Select', - widget: 'choicesjs', - tableView: true, - key: 'component', - template: '{{ item.label }}', - type: 'select', - input: true, - lazyLoad: false, - disableLimit: false, -}; -exports.simpleRadioField = { - label: 'Radio', - dataSrc: 'values', - optionsLabelPosition: 'right', - inline: false, - tableView: false, - values: [ - { - label: 'foo', - value: 'foo', - shortcut: '', - }, - { - label: 'bar', - value: 'bar', - shortcut: '', - }, - { - label: 'baz', - value: 'baz', - shortcut: '', - }, - { - label: 'biz', - value: 'biz', - shortcut: '', - }, - ], - key: 'component', - type: 'radio', - input: true, -}; -exports.hiddenRequiredField = { - type: 'hidden', - key: 'someData', - input: true, - validate: { - required: true - } -}; -exports.conditionallyHiddenRequiredHiddenField = { - type: 'hidden', - key: 'someData', - input: true, - validate: { - required: true - }, - conditional: { - show: false, - when: 'otherData', - eq: 'hideme' - } -}; -exports.requiredNonInputField = { - type: 'well', - key: 'someData', - input: false, - validate: { - required: true - } -}; diff --git a/src/process/validation/rules/__tests__/fixtures/components.ts b/src/process/validation/rules/__tests__/fixtures/components.ts index f39f5137..ed8fca0c 100644 --- a/src/process/validation/rules/__tests__/fixtures/components.ts +++ b/src/process/validation/rules/__tests__/fixtures/components.ts @@ -1,245 +1,244 @@ import { - DateTimeComponent, - DayComponent, - HiddenComponent, - NumberComponent, - RadioComponent, - SelectBoxesComponent, - SelectComponentOptions, - TextFieldComponent, - WellComponent, + DateTimeComponent, + DayComponent, + HiddenComponent, + NumberComponent, + RadioComponent, + SelectBoxesComponent, + SelectComponentOptions, + TextFieldComponent, } from 'types'; export const simpleTextField: TextFieldComponent = { - type: 'textField', - label: 'Simple Text Field', - input: true, - tableView: true, - key: 'component', + type: 'textField', + label: 'Simple Text Field', + input: true, + tableView: true, + key: 'component', }; export const simpleDateTimeField: DateTimeComponent = { - tableView: false, - label: 'Simple Date/Time', - datePicker: { - disableWeekends: false, - disableWeekdays: false, - }, - enableMinDateInput: false, - enableMaxDateInput: false, - enableDate: true, - key: 'component', - type: 'datetime', - input: true, - widget: { - type: 'calendar', - displayInTimezone: 'viewer', - locale: 'en', - useLocaleSettings: false, - allowInput: true, - mode: 'single', - enableTime: true, - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - hourIncrement: 1, - minuteIncrement: 1, - time_24hr: false, - disableWeekends: false, - disableWeekdays: false, - }, + tableView: false, + label: 'Simple Date/Time', + datePicker: { + disableWeekends: false, + disableWeekdays: false, + }, + enableMinDateInput: false, + enableMaxDateInput: false, + enableDate: true, + key: 'component', + type: 'datetime', + input: true, + widget: { + type: 'calendar', + displayInTimezone: 'viewer', + locale: 'en', + useLocaleSettings: false, + allowInput: true, + mode: 'single', + enableTime: true, + noCalendar: false, + format: 'yyyy-MM-dd hh:mm a', + hourIncrement: 1, + minuteIncrement: 1, + time_24hr: false, + disableWeekends: false, + disableWeekdays: false, + }, }; export const simpleDayField: DayComponent = { - label: 'Simple Day', - hideInputLabels: false, - inputsLabelPosition: 'top', - useLocaleSettings: false, - tableView: false, - fields: { - day: { - hide: false, - }, - month: { - hide: false, - }, - year: { - hide: false, - }, + label: 'Simple Day', + hideInputLabels: false, + inputsLabelPosition: 'top', + useLocaleSettings: false, + tableView: false, + fields: { + day: { + hide: false, }, - key: 'component', - type: 'day', - input: true, - defaultValue: '00/00/0000', + month: { + hide: false, + }, + year: { + hide: false, + }, + }, + key: 'component', + type: 'day', + input: true, + defaultValue: '00/00/0000', }; export const calendarTextField: TextFieldComponent = { - label: 'Text Field', - widget: { - type: 'calendar', - altInput: true, - allowInput: true, - clickOpens: true, - // enableDate: true, - enableTime: true, - mode: 'single', - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-ddTHH:mm:ssZ', - useLocaleSettings: false, - hourIncrement: 1, - minuteIncrement: 5, - time_24hr: false, - saveAs: 'text', - displayInTimezone: 'viewer', - locale: 'en', - }, - tableView: true, - key: 'component', - type: 'textfield', - input: true, + label: 'Text Field', + widget: { + type: 'calendar', + altInput: true, + allowInput: true, + clickOpens: true, + // enableDate: true, + enableTime: true, + mode: 'single', + noCalendar: false, + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-ddTHH:mm:ssZ', + useLocaleSettings: false, + hourIncrement: 1, + minuteIncrement: 5, + time_24hr: false, + saveAs: 'text', + displayInTimezone: 'viewer', + locale: 'en', + }, + tableView: true, + key: 'component', + type: 'textfield', + input: true, }; export const simpleEmailField = { - label: 'Email', - tableView: true, - key: 'component', - type: 'email', - input: true, + label: 'Email', + tableView: true, + key: 'component', + type: 'email', + input: true, }; export const simpleSelectBoxes: SelectBoxesComponent = { - label: 'Select Boxes', - optionsLabelPosition: 'right', - tableView: false, - values: [ - { - label: 'foo', - value: 'foo', - }, - { - label: 'bar', - value: 'bar', - }, - { - label: 'baz', - value: 'baz', - }, - { - label: 'biz', - value: 'biz', - }, - ], - validate: { - maxSelectedCount: 3, + label: 'Select Boxes', + optionsLabelPosition: 'right', + tableView: false, + values: [ + { + label: 'foo', + value: 'foo', }, - key: 'component', - type: 'selectboxes', - input: true, - inputType: 'checkbox', + { + label: 'bar', + value: 'bar', + }, + { + label: 'baz', + value: 'baz', + }, + { + label: 'biz', + value: 'biz', + }, + ], + validate: { + maxSelectedCount: 3, + }, + key: 'component', + type: 'selectboxes', + input: true, + inputType: 'checkbox', }; export const simpleNumberField: NumberComponent = { - label: 'Number', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - truncateMultipleSpaces: false, - key: 'component', - type: 'number', - input: true, + label: 'Number', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + truncateMultipleSpaces: false, + key: 'component', + type: 'number', + input: true, }; export const simpleUrlField = { - label: 'Url', - tableView: true, - key: 'component', - type: 'url', - input: true, + label: 'Url', + tableView: true, + key: 'component', + type: 'url', + input: true, }; export const simpleSelectOptions: SelectComponentOptions = { - label: 'Select', - widget: 'choicesjs', - tableView: true, - key: 'component', - template: '{{ item.label }}', - type: 'select', - input: true, - lazyLoad: false, - disableLimit: false, + label: 'Select', + widget: 'choicesjs', + tableView: true, + key: 'component', + template: '{{ item.label }}', + type: 'select', + input: true, + lazyLoad: false, + disableLimit: false, }; export const simpleRadioField: RadioComponent = { - label: 'Radio', - dataSrc: 'values', - optionsLabelPosition: 'right', - inline: false, - tableView: false, - values: [ - { - label: 'foo', - value: 'foo', - shortcut: '', - }, - { - label: 'bar', - value: 'bar', - shortcut: '', - }, - { - label: 'baz', - value: 'baz', - shortcut: '', - }, - { - label: 'biz', - value: 'biz', - shortcut: '', - }, - ], - key: 'component', - type: 'radio', - input: true, + label: 'Radio', + dataSrc: 'values', + optionsLabelPosition: 'right', + inline: false, + tableView: false, + values: [ + { + label: 'foo', + value: 'foo', + shortcut: '', + }, + { + label: 'bar', + value: 'bar', + shortcut: '', + }, + { + label: 'baz', + value: 'baz', + shortcut: '', + }, + { + label: 'biz', + value: 'biz', + shortcut: '', + }, + ], + key: 'component', + type: 'radio', + input: true, }; export const simpleCheckBoxField = { - label: 'Checkbox', - tableView: true, - key: 'component', - type: 'checkbox', - input: true, + label: 'Checkbox', + tableView: true, + key: 'component', + type: 'checkbox', + input: true, }; export const hiddenRequiredField: HiddenComponent = { - type: 'hidden', - key: 'someData', - input: true, - validate: { - required: true - } + type: 'hidden', + key: 'someData', + input: true, + validate: { + required: true, + }, }; export const conditionallyHiddenRequiredHiddenField: HiddenComponent = { - type: 'hidden', - key: 'someData', - input: true, - validate: { - required: true - }, - conditional: { - show: false, - when: 'otherData', - eq: 'hideme' - } + type: 'hidden', + key: 'someData', + input: true, + validate: { + required: true, + }, + conditional: { + show: false, + when: 'otherData', + eq: 'hideme', + }, }; export const requiredNonInputField: any = { - type: 'well', - key: 'someData', - input: false, - validate: { - required: true - } + type: 'well', + key: 'someData', + input: false, + validate: { + required: true, + }, }; diff --git a/src/process/validation/rules/__tests__/fixtures/forms.d.ts b/src/process/validation/rules/__tests__/fixtures/forms.d.ts deleted file mode 100644 index 6dd3f738..00000000 --- a/src/process/validation/rules/__tests__/fixtures/forms.d.ts +++ /dev/null @@ -1,5896 +0,0 @@ -export declare const w4: { - _id: string; - machineName: string; - modified: string; - title: string; - display: string; - settings: { - pdf: { - id: string; - src: string; - }; - }; - name: string; - path: string; - project: string; - created: string; - components: ( - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - type: string; - overlay: { - width: number; - height: number; - left: number; - top: number; - page: number; - style: string; - }; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - displayInTimezone?: undefined; - submissionTimezone?: undefined; - locale?: undefined; - useLocaleSettings?: undefined; - allowInput?: undefined; - mode?: undefined; - enableTime?: undefined; - noCalendar?: undefined; - format?: undefined; - hourIncrement?: undefined; - minuteIncrement?: undefined; - time_24hr?: undefined; - minDate?: undefined; - maxDate?: undefined; - }; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - minLength: string; - maxLength: string; - pattern: string; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - mask: boolean; - inputType: string; - inputFormat: string; - inputMask: string; - displayMask: string; - spellcheck: boolean; - truncateMultipleSpaces: boolean; - id: string; - datePicker?: undefined; - format?: undefined; - useLocaleSettings?: undefined; - allowInput?: undefined; - enableDate?: undefined; - enableTime?: undefined; - defaultDate?: undefined; - displayInTimezone?: undefined; - timezone?: undefined; - datepickerMode?: undefined; - timePicker?: undefined; - customOptions?: undefined; - footer?: undefined; - width?: undefined; - height?: undefined; - penColor?: undefined; - backgroundColor?: undefined; - minWidth?: undefined; - maxWidth?: undefined; - keepOverlayRatio?: undefined; - value?: undefined; - name?: undefined; - datagridLabel?: undefined; - size?: undefined; - leftIcon?: undefined; - rightIcon?: undefined; - block?: undefined; - action?: undefined; - disableOnInvalid?: undefined; - theme?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - datePicker: { - datepickerMode: string; - showWeeks: boolean; - startingDay: number; - initDate: string; - minMode: string; - maxMode: string; - yearRows: number; - yearColumns: number; - minDate: null; - maxDate: null; - }; - type: string; - overlay: { - width: number; - height: number; - left: number; - top: number; - page: number; - style: string; - }; - widget: { - type: string; - displayInTimezone: string; - submissionTimezone: string; - locale: string; - useLocaleSettings: boolean; - allowInput: boolean; - mode: string; - enableTime: boolean; - noCalendar: boolean; - format: string; - hourIncrement: number; - minuteIncrement: number; - time_24hr: boolean; - minDate: null; - maxDate: null; - }; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: string; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - minLength?: undefined; - maxLength?: undefined; - pattern?: undefined; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - format: string; - useLocaleSettings: boolean; - allowInput: boolean; - enableDate: boolean; - enableTime: boolean; - defaultDate: string; - displayInTimezone: string; - timezone: string; - datepickerMode: string; - timePicker: { - hourStep: number; - minuteStep: number; - showMeridian: boolean; - readonlyInput: boolean; - mousewheel: boolean; - arrowkeys: boolean; - }; - customOptions: {}; - id: string; - mask?: undefined; - inputType?: undefined; - inputFormat?: undefined; - inputMask?: undefined; - displayMask?: undefined; - spellcheck?: undefined; - truncateMultipleSpaces?: undefined; - footer?: undefined; - width?: undefined; - height?: undefined; - penColor?: undefined; - backgroundColor?: undefined; - minWidth?: undefined; - maxWidth?: undefined; - keepOverlayRatio?: undefined; - value?: undefined; - name?: undefined; - datagridLabel?: undefined; - size?: undefined; - leftIcon?: undefined; - rightIcon?: undefined; - block?: undefined; - action?: undefined; - disableOnInvalid?: undefined; - theme?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - type: string; - overlay: { - width: number; - height: number; - left: number; - top: number; - page: number; - style: string; - }; - hideLabel: boolean; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - displayInTimezone?: undefined; - submissionTimezone?: undefined; - locale?: undefined; - useLocaleSettings?: undefined; - allowInput?: undefined; - mode?: undefined; - enableTime?: undefined; - noCalendar?: undefined; - format?: undefined; - hourIncrement?: undefined; - minuteIncrement?: undefined; - time_24hr?: undefined; - minDate?: undefined; - maxDate?: undefined; - }; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - minLength?: undefined; - maxLength?: undefined; - pattern?: undefined; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - footer: string; - width: string; - height: string; - penColor: string; - backgroundColor: string; - minWidth: string; - maxWidth: string; - keepOverlayRatio: boolean; - id: string; - mask?: undefined; - inputType?: undefined; - inputFormat?: undefined; - inputMask?: undefined; - displayMask?: undefined; - spellcheck?: undefined; - truncateMultipleSpaces?: undefined; - datePicker?: undefined; - format?: undefined; - useLocaleSettings?: undefined; - allowInput?: undefined; - enableDate?: undefined; - enableTime?: undefined; - defaultDate?: undefined; - displayInTimezone?: undefined; - timezone?: undefined; - datepickerMode?: undefined; - timePicker?: undefined; - customOptions?: undefined; - value?: undefined; - name?: undefined; - datagridLabel?: undefined; - size?: undefined; - leftIcon?: undefined; - rightIcon?: undefined; - block?: undefined; - action?: undefined; - disableOnInvalid?: undefined; - theme?: undefined; - } - | { - hideLabel: boolean; - overlay: { - page: number; - top: number; - left: number; - height: number; - width: number; - style: string; - }; - type: string; - value: string; - name: string; - defaultValue: boolean; - key: string; - datagridLabel: boolean; - label: string; - tableView: boolean; - inputType: string; - input: boolean; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: null; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - minLength?: undefined; - maxLength?: undefined; - pattern?: undefined; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - id: string; - mask?: undefined; - inputFormat?: undefined; - inputMask?: undefined; - displayMask?: undefined; - spellcheck?: undefined; - truncateMultipleSpaces?: undefined; - datePicker?: undefined; - format?: undefined; - useLocaleSettings?: undefined; - allowInput?: undefined; - enableDate?: undefined; - enableTime?: undefined; - defaultDate?: undefined; - displayInTimezone?: undefined; - timezone?: undefined; - datepickerMode?: undefined; - timePicker?: undefined; - customOptions?: undefined; - footer?: undefined; - width?: undefined; - height?: undefined; - penColor?: undefined; - backgroundColor?: undefined; - minWidth?: undefined; - maxWidth?: undefined; - keepOverlayRatio?: undefined; - size?: undefined; - leftIcon?: undefined; - rightIcon?: undefined; - block?: undefined; - action?: undefined; - disableOnInvalid?: undefined; - theme?: undefined; - } - | { - overlay: { - page: number; - top: number; - left: number; - height: string; - width: string; - style: string; - }; - type: string; - key: string; - label: string; - tableView: boolean; - input: boolean; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - displayInTimezone?: undefined; - submissionTimezone?: undefined; - locale?: undefined; - useLocaleSettings?: undefined; - allowInput?: undefined; - mode?: undefined; - enableTime?: undefined; - noCalendar?: undefined; - format?: undefined; - hourIncrement?: undefined; - minuteIncrement?: undefined; - time_24hr?: undefined; - minDate?: undefined; - maxDate?: undefined; - }; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - minLength: string; - maxLength: string; - pattern: string; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - mask: boolean; - inputType: string; - inputFormat: string; - inputMask: string; - displayMask: string; - spellcheck: boolean; - truncateMultipleSpaces: boolean; - id: string; - datePicker?: undefined; - format?: undefined; - useLocaleSettings?: undefined; - allowInput?: undefined; - enableDate?: undefined; - enableTime?: undefined; - defaultDate?: undefined; - displayInTimezone?: undefined; - timezone?: undefined; - datepickerMode?: undefined; - timePicker?: undefined; - customOptions?: undefined; - footer?: undefined; - width?: undefined; - height?: undefined; - penColor?: undefined; - backgroundColor?: undefined; - minWidth?: undefined; - maxWidth?: undefined; - keepOverlayRatio?: undefined; - value?: undefined; - name?: undefined; - datagridLabel?: undefined; - size?: undefined; - leftIcon?: undefined; - rightIcon?: undefined; - block?: undefined; - action?: undefined; - disableOnInvalid?: undefined; - theme?: undefined; - } - | { - input: boolean; - label: string; - tableView: boolean; - key: string; - type: string; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - displayInTimezone?: undefined; - submissionTimezone?: undefined; - locale?: undefined; - useLocaleSettings?: undefined; - allowInput?: undefined; - mode?: undefined; - enableTime?: undefined; - noCalendar?: undefined; - format?: undefined; - hourIncrement?: undefined; - minuteIncrement?: undefined; - time_24hr?: undefined; - minDate?: undefined; - maxDate?: undefined; - }; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - minLength?: undefined; - maxLength?: undefined; - pattern?: undefined; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - page?: undefined; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - size: string; - leftIcon: string; - rightIcon: string; - block: boolean; - action: string; - disableOnInvalid: boolean; - theme: string; - id: string; - mask?: undefined; - inputType?: undefined; - inputFormat?: undefined; - inputMask?: undefined; - displayMask?: undefined; - spellcheck?: undefined; - truncateMultipleSpaces?: undefined; - datePicker?: undefined; - format?: undefined; - useLocaleSettings?: undefined; - allowInput?: undefined; - enableDate?: undefined; - enableTime?: undefined; - defaultDate?: undefined; - displayInTimezone?: undefined; - timezone?: undefined; - datepickerMode?: undefined; - timePicker?: undefined; - customOptions?: undefined; - footer?: undefined; - width?: undefined; - height?: undefined; - penColor?: undefined; - backgroundColor?: undefined; - minWidth?: undefined; - maxWidth?: undefined; - keepOverlayRatio?: undefined; - value?: undefined; - name?: undefined; - datagridLabel?: undefined; - } - )[]; - owner: string; - submissionAccess: { - roles: never[]; - type: string; - }[]; - access: { - roles: string[]; - type: string; - }[]; - tags: never[]; - type: string; - _vid: number; - revisions: string; -}; -export declare const example: { - _id: string; - machineName: string; - modified: string; - title: string; - display: string; - type: string; - name: string; - path: string; - project: string; - created: string; - components: ( - | { - input: boolean; - html: string; - type: string; - conditional: { - show: string; - when: null; - eq: string; - }; - key: string; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - tableView: boolean; - modalEdit: boolean; - label: string; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: null; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - id: string; - addons: never[]; - columns?: undefined; - tree?: undefined; - autoAdjust?: undefined; - lazyLoad?: undefined; - tags?: undefined; - questions?: undefined; - values?: undefined; - footer?: undefined; - width?: undefined; - height?: undefined; - penColor?: undefined; - backgroundColor?: undefined; - minWidth?: undefined; - maxWidth?: undefined; - keepOverlayRatio?: undefined; - size?: undefined; - leftIcon?: undefined; - rightIcon?: undefined; - block?: undefined; - action?: undefined; - disableOnInvalid?: undefined; - theme?: undefined; - } - | { - input: boolean; - columns: ( - | { - components: ( - | { - tabindex: string; - tags: never[]; - clearOnHide: boolean; - hidden: boolean; - input: boolean; - tableView: boolean; - inputType: string; - inputMask: string; - label: string; - key: string; - placeholder: string; - prefix: string; - suffix: string; - multiple: boolean; - defaultValue: string; - protected: boolean; - unique: boolean; - persistent: boolean; - validate: { - required: boolean; - minLength: string; - maxLength: string; - pattern: string; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - }; - conditional: { - show: string; - when: null; - eq: string; - }; - type: string; - customClass: string; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - }; - attributes: {}; - validateOn: string; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - mask: boolean; - inputFormat: string; - spellcheck: boolean; - id: string; - addons: never[]; - displayMask: string; - truncateMultipleSpaces: boolean; - kickbox?: undefined; - } - | { - tabindex: string; - tags: never[]; - clearOnHide: boolean; - hidden: boolean; - input: boolean; - tableView: boolean; - inputType: string; - label: string; - key: string; - placeholder: string; - prefix: string; - suffix: string; - defaultValue: string; - protected: boolean; - unique: boolean; - persistent: boolean; - type: string; - conditional: { - show: string; - when: null; - eq: string; - }; - kickbox: { - enabled: boolean; - }; - customClass: string; - multiple: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - }; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - minLength: string; - maxLength: string; - pattern: string; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - mask: boolean; - inputFormat: string; - inputMask: string; - spellcheck: boolean; - id: string; - addons: never[]; - displayMask: string; - truncateMultipleSpaces: boolean; - } - )[]; - width: number; - offset: number; - push: number; - pull: number; - size: string; - currentWidth: number; - } - | { - components: ( - | { - tabindex: string; - tags: never[]; - clearOnHide: boolean; - hidden: boolean; - input: boolean; - tableView: boolean; - inputType: string; - inputMask: string; - label: string; - key: string; - placeholder: string; - prefix: string; - suffix: string; - multiple: boolean; - defaultValue: string; - protected: boolean; - unique: boolean; - persistent: boolean; - validate: { - required: boolean; - minLength: string; - maxLength: string; - pattern: string; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - }; - conditional: { - show: string; - when: null; - eq: string; - }; - type: string; - customClass: string; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - }; - attributes: {}; - validateOn: string; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - mask: boolean; - inputFormat: string; - spellcheck: boolean; - id: string; - addons: never[]; - displayMask: string; - truncateMultipleSpaces: boolean; - inputMode?: undefined; - } - | { - tabindex: string; - tags: never[]; - clearOnHide: boolean; - hidden: boolean; - input: boolean; - tableView: boolean; - inputMask: string; - label: string; - key: string; - placeholder: string; - prefix: string; - suffix: string; - multiple: boolean; - protected: boolean; - unique: boolean; - persistent: boolean; - defaultValue: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - minLength: string; - maxLength: string; - pattern: string; - }; - type: string; - conditional: { - show: string; - when: null; - eq: string; - }; - customClass: string; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - }; - attributes: {}; - validateOn: string; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - mask: boolean; - inputType: string; - inputFormat: string; - spellcheck: boolean; - inputMode: string; - id: string; - addons: never[]; - displayMask: string; - truncateMultipleSpaces: boolean; - } - )[]; - width: number; - offset: number; - push: number; - pull: number; - size: string; - currentWidth: number; - } - )[]; - type: string; - conditional: { - show: string; - when: null; - eq: string; - }; - key: string; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - tableView: boolean; - modalEdit: boolean; - label: string; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: null; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - tree: boolean; - autoAdjust: boolean; - id: string; - addons: never[]; - lazyLoad: boolean; - html?: undefined; - tags?: undefined; - questions?: undefined; - values?: undefined; - footer?: undefined; - width?: undefined; - height?: undefined; - penColor?: undefined; - backgroundColor?: undefined; - minWidth?: undefined; - maxWidth?: undefined; - keepOverlayRatio?: undefined; - size?: undefined; - leftIcon?: undefined; - rightIcon?: undefined; - block?: undefined; - action?: undefined; - disableOnInvalid?: undefined; - theme?: undefined; - } - | { - tabindex: string; - tags: never[]; - clearOnHide: boolean; - hidden: boolean; - input: boolean; - tableView: boolean; - label: string; - key: string; - questions: { - value: string; - label: string; - }[]; - values: { - value: string; - label: string; - }[]; - defaultValue: string; - protected: boolean; - persistent: boolean; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - }; - type: string; - conditional: { - show: string; - when: null; - eq: string; - }; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - unique: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: null; - attributes: {}; - validateOn: string; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - id: string; - addons: never[]; - html?: undefined; - columns?: undefined; - tree?: undefined; - autoAdjust?: undefined; - lazyLoad?: undefined; - footer?: undefined; - width?: undefined; - height?: undefined; - penColor?: undefined; - backgroundColor?: undefined; - minWidth?: undefined; - maxWidth?: undefined; - keepOverlayRatio?: undefined; - size?: undefined; - leftIcon?: undefined; - rightIcon?: undefined; - block?: undefined; - action?: undefined; - disableOnInvalid?: undefined; - theme?: undefined; - } - | { - tags: never[]; - clearOnHide: boolean; - hidden: boolean; - input: boolean; - tableView: boolean; - label: string; - key: string; - placeholder: string; - footer: string; - width: string; - height: string; - penColor: string; - backgroundColor: string; - minWidth: string; - maxWidth: string; - protected: boolean; - persistent: boolean; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - }; - type: string; - hideLabel: boolean; - conditional: { - show: string; - when: null; - eq: string; - }; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - unique: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - }; - attributes: {}; - validateOn: string; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - id: string; - addons: never[]; - keepOverlayRatio: boolean; - html?: undefined; - columns?: undefined; - tree?: undefined; - autoAdjust?: undefined; - lazyLoad?: undefined; - questions?: undefined; - values?: undefined; - size?: undefined; - leftIcon?: undefined; - rightIcon?: undefined; - block?: undefined; - action?: undefined; - disableOnInvalid?: undefined; - theme?: undefined; - } - | { - tabindex: string; - conditional: { - eq: string; - when: null; - show: string; - }; - tags: never[]; - input: boolean; - label: string; - tableView: boolean; - key: string; - size: string; - leftIcon: string; - rightIcon: string; - block: boolean; - action: string; - disableOnInvalid: boolean; - theme: string; - type: string; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - }; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - id: string; - addons: never[]; - html?: undefined; - columns?: undefined; - tree?: undefined; - autoAdjust?: undefined; - lazyLoad?: undefined; - questions?: undefined; - values?: undefined; - footer?: undefined; - width?: undefined; - height?: undefined; - penColor?: undefined; - backgroundColor?: undefined; - minWidth?: undefined; - maxWidth?: undefined; - keepOverlayRatio?: undefined; - } - )[]; - owner: string; - submissionAccess: { - roles: string[]; - type: string; - }[]; - access: { - roles: string[]; - type: string; - }[]; - tags: never[]; - _vid: number; - revisions: string; -}; -export declare const simpleForm: { - _id: string; - title: string; - name: string; - path: string; - type: string; - display: string; - tags: never[]; - components: ( - | { - label: string; - applyMaskOn: string; - tableView: boolean; - validate: { - required: boolean; - maxWords?: undefined; - minWords?: undefined; - custom?: undefined; - customPrivate?: undefined; - strictDateValidation?: undefined; - multiple?: undefined; - unique?: undefined; - minLength?: undefined; - maxLength?: undefined; - pattern?: undefined; - }; - key: string; - type: string; - input: boolean; - autoExpand?: undefined; - placeholder?: undefined; - prefix?: undefined; - customClass?: undefined; - suffix?: undefined; - multiple?: undefined; - defaultValue?: undefined; - protected?: undefined; - unique?: undefined; - persistent?: undefined; - hidden?: undefined; - clearOnHide?: undefined; - refreshOn?: undefined; - redrawOn?: undefined; - modalEdit?: undefined; - dataGridLabel?: undefined; - labelPosition?: undefined; - description?: undefined; - errorLabel?: undefined; - tooltip?: undefined; - hideLabel?: undefined; - tabindex?: undefined; - disabled?: undefined; - autofocus?: undefined; - dbIndex?: undefined; - customDefaultValue?: undefined; - calculateValue?: undefined; - calculateServer?: undefined; - widget?: undefined; - attributes?: undefined; - validateOn?: undefined; - conditional?: undefined; - overlay?: undefined; - allowCalculateOverride?: undefined; - encrypted?: undefined; - showCharCount?: undefined; - showWordCount?: undefined; - properties?: undefined; - allowMultipleMasks?: undefined; - addons?: undefined; - mask?: undefined; - inputType?: undefined; - inputFormat?: undefined; - inputMask?: undefined; - displayMask?: undefined; - spellcheck?: undefined; - truncateMultipleSpaces?: undefined; - inputMode?: undefined; - id?: undefined; - keyModified?: undefined; - disableOnInvalid?: undefined; - } - | { - label: string; - applyMaskOn: string; - autoExpand: boolean; - tableView: boolean; - validate: { - maxWords: number; - required?: undefined; - minWords?: undefined; - custom?: undefined; - customPrivate?: undefined; - strictDateValidation?: undefined; - multiple?: undefined; - unique?: undefined; - minLength?: undefined; - maxLength?: undefined; - pattern?: undefined; - }; - key: string; - type: string; - input: boolean; - placeholder?: undefined; - prefix?: undefined; - customClass?: undefined; - suffix?: undefined; - multiple?: undefined; - defaultValue?: undefined; - protected?: undefined; - unique?: undefined; - persistent?: undefined; - hidden?: undefined; - clearOnHide?: undefined; - refreshOn?: undefined; - redrawOn?: undefined; - modalEdit?: undefined; - dataGridLabel?: undefined; - labelPosition?: undefined; - description?: undefined; - errorLabel?: undefined; - tooltip?: undefined; - hideLabel?: undefined; - tabindex?: undefined; - disabled?: undefined; - autofocus?: undefined; - dbIndex?: undefined; - customDefaultValue?: undefined; - calculateValue?: undefined; - calculateServer?: undefined; - widget?: undefined; - attributes?: undefined; - validateOn?: undefined; - conditional?: undefined; - overlay?: undefined; - allowCalculateOverride?: undefined; - encrypted?: undefined; - showCharCount?: undefined; - showWordCount?: undefined; - properties?: undefined; - allowMultipleMasks?: undefined; - addons?: undefined; - mask?: undefined; - inputType?: undefined; - inputFormat?: undefined; - inputMask?: undefined; - displayMask?: undefined; - spellcheck?: undefined; - truncateMultipleSpaces?: undefined; - inputMode?: undefined; - id?: undefined; - keyModified?: undefined; - disableOnInvalid?: undefined; - } - | { - label: string; - applyMaskOn: string; - autoExpand: boolean; - tableView: boolean; - validate: { - minWords: number; - required?: undefined; - maxWords?: undefined; - custom?: undefined; - customPrivate?: undefined; - strictDateValidation?: undefined; - multiple?: undefined; - unique?: undefined; - minLength?: undefined; - maxLength?: undefined; - pattern?: undefined; - }; - key: string; - type: string; - input: boolean; - placeholder?: undefined; - prefix?: undefined; - customClass?: undefined; - suffix?: undefined; - multiple?: undefined; - defaultValue?: undefined; - protected?: undefined; - unique?: undefined; - persistent?: undefined; - hidden?: undefined; - clearOnHide?: undefined; - refreshOn?: undefined; - redrawOn?: undefined; - modalEdit?: undefined; - dataGridLabel?: undefined; - labelPosition?: undefined; - description?: undefined; - errorLabel?: undefined; - tooltip?: undefined; - hideLabel?: undefined; - tabindex?: undefined; - disabled?: undefined; - autofocus?: undefined; - dbIndex?: undefined; - customDefaultValue?: undefined; - calculateValue?: undefined; - calculateServer?: undefined; - widget?: undefined; - attributes?: undefined; - validateOn?: undefined; - conditional?: undefined; - overlay?: undefined; - allowCalculateOverride?: undefined; - encrypted?: undefined; - showCharCount?: undefined; - showWordCount?: undefined; - properties?: undefined; - allowMultipleMasks?: undefined; - addons?: undefined; - mask?: undefined; - inputType?: undefined; - inputFormat?: undefined; - inputMask?: undefined; - displayMask?: undefined; - spellcheck?: undefined; - truncateMultipleSpaces?: undefined; - inputMode?: undefined; - id?: undefined; - keyModified?: undefined; - disableOnInvalid?: undefined; - } - | { - label: string; - applyMaskOn: string; - tableView: boolean; - key: string; - type: string; - input: boolean; - validate?: undefined; - autoExpand?: undefined; - placeholder?: undefined; - prefix?: undefined; - customClass?: undefined; - suffix?: undefined; - multiple?: undefined; - defaultValue?: undefined; - protected?: undefined; - unique?: undefined; - persistent?: undefined; - hidden?: undefined; - clearOnHide?: undefined; - refreshOn?: undefined; - redrawOn?: undefined; - modalEdit?: undefined; - dataGridLabel?: undefined; - labelPosition?: undefined; - description?: undefined; - errorLabel?: undefined; - tooltip?: undefined; - hideLabel?: undefined; - tabindex?: undefined; - disabled?: undefined; - autofocus?: undefined; - dbIndex?: undefined; - customDefaultValue?: undefined; - calculateValue?: undefined; - calculateServer?: undefined; - widget?: undefined; - attributes?: undefined; - validateOn?: undefined; - conditional?: undefined; - overlay?: undefined; - allowCalculateOverride?: undefined; - encrypted?: undefined; - showCharCount?: undefined; - showWordCount?: undefined; - properties?: undefined; - allowMultipleMasks?: undefined; - addons?: undefined; - mask?: undefined; - inputType?: undefined; - inputFormat?: undefined; - inputMask?: undefined; - displayMask?: undefined; - spellcheck?: undefined; - truncateMultipleSpaces?: undefined; - inputMode?: undefined; - id?: undefined; - keyModified?: undefined; - disableOnInvalid?: undefined; - } - | { - label: string; - applyMaskOn: string; - tableView: boolean; - key: string; - type: string; - input: boolean; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - }; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - minLength: string; - maxLength: string; - pattern: string; - maxWords?: undefined; - minWords?: undefined; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - mask: boolean; - inputType: string; - inputFormat: string; - inputMask: string; - displayMask: string; - spellcheck: boolean; - truncateMultipleSpaces: boolean; - inputMode: string; - id: string; - keyModified: boolean; - autoExpand?: undefined; - disableOnInvalid?: undefined; - } - | { - type: string; - label: string; - key: string; - disableOnInvalid: boolean; - input: boolean; - tableView: boolean; - applyMaskOn?: undefined; - validate?: undefined; - autoExpand?: undefined; - placeholder?: undefined; - prefix?: undefined; - customClass?: undefined; - suffix?: undefined; - multiple?: undefined; - defaultValue?: undefined; - protected?: undefined; - unique?: undefined; - persistent?: undefined; - hidden?: undefined; - clearOnHide?: undefined; - refreshOn?: undefined; - redrawOn?: undefined; - modalEdit?: undefined; - dataGridLabel?: undefined; - labelPosition?: undefined; - description?: undefined; - errorLabel?: undefined; - tooltip?: undefined; - hideLabel?: undefined; - tabindex?: undefined; - disabled?: undefined; - autofocus?: undefined; - dbIndex?: undefined; - customDefaultValue?: undefined; - calculateValue?: undefined; - calculateServer?: undefined; - widget?: undefined; - attributes?: undefined; - validateOn?: undefined; - conditional?: undefined; - overlay?: undefined; - allowCalculateOverride?: undefined; - encrypted?: undefined; - showCharCount?: undefined; - showWordCount?: undefined; - properties?: undefined; - allowMultipleMasks?: undefined; - addons?: undefined; - mask?: undefined; - inputType?: undefined; - inputFormat?: undefined; - inputMask?: undefined; - displayMask?: undefined; - spellcheck?: undefined; - truncateMultipleSpaces?: undefined; - inputMode?: undefined; - id?: undefined; - keyModified?: undefined; - } - )[]; - settings: {}; - properties: {}; - project: string; - controller: string; - revisions: string; - submissionRevisions: string; - _vid: number; - created: string; - modified: string; - machineName: string; -}; -export declare const wizard: { - _id: string; - machineName: string; - modified: string; - title: string; - display: string; - type: string; - name: string; - path: string; - project: string; - created: string; - components: ( - | { - key: string; - input: boolean; - components: ( - | { - type: string; - multiple: boolean; - key: string; - label: string; - tableView: boolean; - input: boolean; - validate?: undefined; - defaultValue?: undefined; - inputType?: undefined; - } - | { - type: string; - validate: { - required: boolean; - }; - defaultValue: number; - key: string; - label: string; - inputType: string; - tableView: boolean; - input: boolean; - multiple?: undefined; - } - )[]; - title: string; - type: string; - tableView: boolean; - label: string; - disableOnInvalid?: undefined; - } - | { - tableView: boolean; - key: string; - input: boolean; - components: ( - | { - type: string; - validate: { - required: boolean; - }; - key: string; - label: string; - tableView: boolean; - input: boolean; - placeholder?: undefined; - data?: undefined; - dataSrc?: undefined; - valueProperty?: undefined; - template?: undefined; - widget?: undefined; - searchField?: undefined; - clearOnHide?: undefined; - components?: undefined; - legend?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - placeholder: string; - data: { - url: string; - headers: { - value: string; - key: string; - }[]; - }; - dataSrc: string; - valueProperty: string; - template: string; - type: string; - widget: string; - searchField: string; - validate?: undefined; - clearOnHide?: undefined; - components?: undefined; - legend?: undefined; - } - | { - clearOnHide: boolean; - type: string; - components: { - type: string; - key: string; - label: string; - tableView: boolean; - input: boolean; - }[]; - legend: string; - tableView: boolean; - input: boolean; - key: string; - label: string; - validate?: undefined; - placeholder?: undefined; - data?: undefined; - dataSrc?: undefined; - valueProperty?: undefined; - template?: undefined; - widget?: undefined; - searchField?: undefined; - } - )[]; - title: string; - type: string; - label: string; - disableOnInvalid?: undefined; - } - | { - type: string; - components: ( - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - validate: { - required: boolean; - }; - type: string; - components?: undefined; - data?: undefined; - widget?: undefined; - } - | { - type: string; - key: string; - label: string; - tableView: boolean; - components: { - hideLabel: boolean; - type: string; - key: string; - label: string; - tableView: boolean; - input: boolean; - inDataGrid: boolean; - }[]; - input: boolean; - validate?: undefined; - data?: undefined; - widget?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - data: { - values: { - value: string; - label: string; - }[]; - }; - widget: string; - type: string; - validate?: undefined; - components?: undefined; - } - )[]; - tableView: boolean; - title: string; - input: boolean; - key: string; - label: string; - disableOnInvalid?: undefined; - } - | { - key: string; - input: boolean; - components: ( - | { - type: string; - key: string; - label: string; - tableView: boolean; - input: boolean; - dataGridLabel?: undefined; - defaultValue?: undefined; - hideLabel?: undefined; - lockKey?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - dataGridLabel: boolean; - key: string; - defaultValue: boolean; - type: string; - hideLabel?: undefined; - lockKey?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - type: string; - hideLabel: boolean; - lockKey: boolean; - dataGridLabel?: undefined; - defaultValue?: undefined; - } - )[]; - title: string; - type: string; - tableView: boolean; - label: string; - disableOnInvalid?: undefined; - } - | { - type: string; - disableOnInvalid: boolean; - key: string; - tableView: boolean; - label: string; - input: boolean; - components?: undefined; - title?: undefined; - } - )[]; - owner: string; - submissionAccess: { - roles: string[]; - type: string; - }[]; - access: { - roles: string[]; - type: string; - }[]; - tags: string[]; - settings: { - controller: string; - }; - revisions: string; - _vid: number; - controller: string; - properties: {}; -}; -export declare const inlineEmbedFormPortal: { - _id: string; - type: string; - tags: never[]; - owner: string; - components: ( - | { - label: string; - tag: string; - attrs: { - attr: string; - value: string; - }[]; - content: string; - refreshOnChange: boolean; - key: string; - type: string; - input: boolean; - tableView: boolean; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: null; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - id: string; - action?: undefined; - showValidations?: undefined; - theme?: undefined; - block?: undefined; - leftIcon?: undefined; - custom?: undefined; - hideOnChildrenHidden?: undefined; - size?: undefined; - rightIcon?: undefined; - disableOnInvalid?: undefined; - title?: undefined; - collapsible?: undefined; - components?: undefined; - tree?: undefined; - lazyLoad?: undefined; - breadcrumb?: undefined; - } - | { - label: string; - action: string; - showValidations: boolean; - theme: string; - block: boolean; - leftIcon: string; - tableView: boolean; - key: string; - type: string; - custom: string; - input: boolean; - hideOnChildrenHidden: boolean; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - }; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - size: string; - rightIcon: string; - disableOnInvalid: boolean; - id: string; - tag?: undefined; - attrs?: undefined; - content?: undefined; - refreshOnChange?: undefined; - title?: undefined; - collapsible?: undefined; - components?: undefined; - tree?: undefined; - lazyLoad?: undefined; - breadcrumb?: undefined; - } - | { - title: string; - collapsible: boolean; - key: string; - type: string; - label: string; - input: boolean; - tableView: boolean; - components: ( - | { - label: string; - customDefaultValue: string; - key: string; - type: string; - tableView: boolean; - input: boolean; - mask: boolean; - inputType: string; - inputFormat: string; - spellcheck: boolean; - hideOnChildrenHidden: boolean; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - }; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - onlyAvailableItems?: undefined; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - id: string; - data?: undefined; - idPath?: undefined; - clearOnRefresh?: undefined; - limit?: undefined; - dataSrc?: undefined; - valueProperty?: undefined; - lazyLoad?: undefined; - filter?: undefined; - searchEnabled?: undefined; - searchDebounce?: undefined; - searchField?: undefined; - minSearch?: undefined; - readOnlyValue?: undefined; - authenticate?: undefined; - ignoreCache?: undefined; - template?: undefined; - selectFields?: undefined; - selectThreshold?: undefined; - uniqueOptions?: undefined; - fuseOptions?: undefined; - indexeddb?: undefined; - customOptions?: undefined; - useExactSearch?: undefined; - title?: undefined; - collapsible?: undefined; - components?: undefined; - collapsed?: undefined; - tree?: undefined; - theme?: undefined; - breadcrumb?: undefined; - } - | { - label: string; - customDefaultValue: string; - key: string; - type: string; - input: boolean; - tableView: boolean; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - }; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - onlyAvailableItems?: undefined; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - inputType: string; - id: string; - mask?: undefined; - inputFormat?: undefined; - spellcheck?: undefined; - hideOnChildrenHidden?: undefined; - data?: undefined; - idPath?: undefined; - clearOnRefresh?: undefined; - limit?: undefined; - dataSrc?: undefined; - valueProperty?: undefined; - lazyLoad?: undefined; - filter?: undefined; - searchEnabled?: undefined; - searchDebounce?: undefined; - searchField?: undefined; - minSearch?: undefined; - readOnlyValue?: undefined; - authenticate?: undefined; - ignoreCache?: undefined; - template?: undefined; - selectFields?: undefined; - selectThreshold?: undefined; - uniqueOptions?: undefined; - fuseOptions?: undefined; - indexeddb?: undefined; - customOptions?: undefined; - useExactSearch?: undefined; - title?: undefined; - collapsible?: undefined; - components?: undefined; - collapsed?: undefined; - tree?: undefined; - theme?: undefined; - breadcrumb?: undefined; - } - | { - label: string; - widget: string; - tableView: boolean; - data: { - values: { - label: string; - value: string; - }[]; - json: string; - url: string; - resource: string; - custom: string; - }; - key: string; - type: string; - input: boolean; - hideOnChildrenHidden: boolean; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - onlyAvailableItems: boolean; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - idPath: string; - clearOnRefresh: boolean; - limit: number; - dataSrc: string; - valueProperty: string; - lazyLoad: boolean; - filter: string; - searchEnabled: boolean; - searchDebounce: number; - searchField: string; - minSearch: number; - readOnlyValue: boolean; - authenticate: boolean; - ignoreCache: boolean; - template: string; - selectFields: string; - selectThreshold: number; - uniqueOptions: boolean; - fuseOptions: { - include: string; - threshold: number; - }; - indexeddb: { - filter: {}; - }; - customOptions: {}; - useExactSearch: boolean; - id: string; - mask?: undefined; - inputType?: undefined; - inputFormat?: undefined; - spellcheck?: undefined; - title?: undefined; - collapsible?: undefined; - components?: undefined; - collapsed?: undefined; - tree?: undefined; - theme?: undefined; - breadcrumb?: undefined; - } - | { - title: string; - collapsible: boolean; - key: string; - type: string; - label: string; - input: boolean; - tableView: boolean; - components: ( - | { - label: string; - tooltip: string; - tableView: boolean; - key: string; - type: string; - input: boolean; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - }; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - minLength: string; - maxLength: string; - pattern: string; - minWords?: undefined; - maxWords?: undefined; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - mask: boolean; - inputType: string; - inputFormat: string; - inputMask: string; - displayMask: string; - spellcheck: boolean; - truncateMultipleSpaces: boolean; - id: string; - calculateValueMode?: undefined; - value?: undefined; - name?: undefined; - editor?: undefined; - autoExpand?: undefined; - as?: undefined; - rows?: undefined; - wysiwyg?: undefined; - fixedSize?: undefined; - } - | { - label: string; - tooltip: string; - tableView: boolean; - defaultValue: boolean; - calculateValue: string; - key: string; - type: string; - input: boolean; - calculateValueMode: string; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateServer: boolean; - widget: null; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - minLength?: undefined; - maxLength?: undefined; - pattern?: undefined; - minWords?: undefined; - maxWords?: undefined; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - inputType: string; - value: string; - name: string; - id: string; - mask?: undefined; - inputFormat?: undefined; - inputMask?: undefined; - displayMask?: undefined; - spellcheck?: undefined; - truncateMultipleSpaces?: undefined; - editor?: undefined; - autoExpand?: undefined; - as?: undefined; - rows?: undefined; - wysiwyg?: undefined; - fixedSize?: undefined; - } - | { - label: string; - tooltip: string; - tableView: boolean; - defaultValue: boolean; - key: string; - type: string; - input: boolean; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: null; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - minLength?: undefined; - maxLength?: undefined; - pattern?: undefined; - minWords?: undefined; - maxWords?: undefined; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - inputType: string; - value: string; - name: string; - id: string; - mask?: undefined; - inputFormat?: undefined; - inputMask?: undefined; - displayMask?: undefined; - spellcheck?: undefined; - truncateMultipleSpaces?: undefined; - calculateValueMode?: undefined; - editor?: undefined; - autoExpand?: undefined; - as?: undefined; - rows?: undefined; - wysiwyg?: undefined; - fixedSize?: undefined; - } - | { - label: string; - description: string; - tooltip: string; - editor: string; - autoExpand: boolean; - tableView: boolean; - key: string; - type: string; - as: string; - input: boolean; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - errorLabel: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: { - type: string; - }; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - minLength: string; - maxLength: string; - pattern: string; - minWords: string; - maxWords: string; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - mask: boolean; - inputType: string; - inputFormat: string; - inputMask: string; - displayMask: string; - spellcheck: boolean; - truncateMultipleSpaces: boolean; - rows: number; - wysiwyg: boolean; - fixedSize: boolean; - id: string; - calculateValueMode?: undefined; - value?: undefined; - name?: undefined; - } - )[]; - collapsed: boolean; - hideOnChildrenHidden: boolean; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: null; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - onlyAvailableItems?: undefined; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - tree: boolean; - lazyLoad: boolean; - theme: string; - breadcrumb: string; - id: string; - mask?: undefined; - inputType?: undefined; - inputFormat?: undefined; - spellcheck?: undefined; - data?: undefined; - idPath?: undefined; - clearOnRefresh?: undefined; - limit?: undefined; - dataSrc?: undefined; - valueProperty?: undefined; - filter?: undefined; - searchEnabled?: undefined; - searchDebounce?: undefined; - searchField?: undefined; - minSearch?: undefined; - readOnlyValue?: undefined; - authenticate?: undefined; - ignoreCache?: undefined; - template?: undefined; - selectFields?: undefined; - selectThreshold?: undefined; - uniqueOptions?: undefined; - fuseOptions?: undefined; - indexeddb?: undefined; - customOptions?: undefined; - useExactSearch?: undefined; - } - )[]; - hideOnChildrenHidden: boolean; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - refreshOn: string; - redrawOn: string; - modalEdit: boolean; - dataGridLabel: boolean; - labelPosition: string; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - calculateServer: boolean; - widget: null; - attributes: {}; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - strictDateValidation: boolean; - multiple: boolean; - unique: boolean; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - overlay: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride: boolean; - encrypted: boolean; - showCharCount: boolean; - showWordCount: boolean; - properties: {}; - allowMultipleMasks: boolean; - addons: never[]; - tree: boolean; - lazyLoad: boolean; - theme: string; - breadcrumb: string; - id: string; - tag?: undefined; - attrs?: undefined; - content?: undefined; - refreshOnChange?: undefined; - action?: undefined; - showValidations?: undefined; - block?: undefined; - leftIcon?: undefined; - custom?: undefined; - size?: undefined; - rightIcon?: undefined; - disableOnInvalid?: undefined; - } - )[]; - revisions: string; - _vid: number; - title: string; - display: string; - access: { - roles: string[]; - type: string; - }[]; - submissionAccess: never[]; - controller: string; - properties: {}; - settings: {}; - name: string; - path: string; - project: string; - created: string; - modified: string; - machineName: string; -}; -export declare const validationRulesNyHealth: { - _id: string; - type: string; - tags: never[]; - owner: string; - components: ( - | { - title: string; - collapsible: boolean; - key: string; - type: string; - label: string; - input: boolean; - tableView: boolean; - components: ( - | { - label: string; - attrs: { - attr: string; - value: string; - }[]; - content: string; - refreshOnChange: boolean; - key: string; - type: string; - input: boolean; - tableView: boolean; - mask?: undefined; - delimiter?: undefined; - requireDecimal?: undefined; - inputFormat?: undefined; - validate?: undefined; - errorLabel?: undefined; - } - | { - label: string; - mask: boolean; - tableView: boolean; - delimiter: boolean; - requireDecimal: boolean; - inputFormat: string; - validate: { - customMessage: string; - custom: string; - }; - errorLabel: string; - key: string; - type: string; - input: boolean; - attrs?: undefined; - content?: undefined; - refreshOnChange?: undefined; - } - | { - label: string; - mask: boolean; - tableView: boolean; - delimiter: boolean; - requireDecimal: boolean; - inputFormat: string; - key: string; - type: string; - input: boolean; - attrs?: undefined; - content?: undefined; - refreshOnChange?: undefined; - validate?: undefined; - errorLabel?: undefined; - } - )[]; - breadcrumbClickable?: undefined; - buttonSettings?: undefined; - scrollToTop?: undefined; - disableOnInvalid?: undefined; - } - | { - title: string; - collapsible: boolean; - key: string; - type: string; - label: string; - input: boolean; - tableView: boolean; - components: ( - | { - label: string; - attrs: { - attr: string; - value: string; - }[]; - content: string; - refreshOnChange: boolean; - key: string; - type: string; - input: boolean; - tableView: boolean; - mask?: undefined; - delimiter?: undefined; - requireDecimal?: undefined; - inputFormat?: undefined; - calculateValue?: undefined; - reorder?: undefined; - addAnotherPosition?: undefined; - layoutFixed?: undefined; - enableRowGroups?: undefined; - initEmpty?: undefined; - defaultValue?: undefined; - components?: undefined; - } - | { - label: string; - mask: boolean; - tableView: boolean; - delimiter: boolean; - requireDecimal: boolean; - inputFormat: string; - calculateValue: string; - key: string; - type: string; - input: boolean; - attrs?: undefined; - content?: undefined; - refreshOnChange?: undefined; - reorder?: undefined; - addAnotherPosition?: undefined; - layoutFixed?: undefined; - enableRowGroups?: undefined; - initEmpty?: undefined; - defaultValue?: undefined; - components?: undefined; - } - | { - label: string; - reorder: boolean; - addAnotherPosition: string; - layoutFixed: boolean; - enableRowGroups: boolean; - initEmpty: boolean; - tableView: boolean; - defaultValue: { - uniqueName: string; - }[]; - key: string; - type: string; - input: boolean; - components: { - label: string; - tableView: boolean; - unique: boolean; - key: string; - type: string; - input: boolean; - }[]; - attrs?: undefined; - content?: undefined; - refreshOnChange?: undefined; - mask?: undefined; - delimiter?: undefined; - requireDecimal?: undefined; - inputFormat?: undefined; - calculateValue?: undefined; - } - )[]; - breadcrumbClickable: boolean; - buttonSettings: { - previous: boolean; - cancel: boolean; - next: boolean; - }; - scrollToTop: boolean; - disableOnInvalid?: undefined; - } - | { - title: string; - collapsible: boolean; - key: string; - type: string; - label: string; - input: boolean; - tableView: boolean; - components: ( - | { - label: string; - attrs: { - attr: string; - value: string; - }[]; - content: string; - refreshOnChange: boolean; - key: string; - type: string; - input: boolean; - tableView: boolean; - title?: undefined; - collapsible?: undefined; - components?: undefined; - } - | { - title: string; - collapsible: boolean; - key: string; - type: string; - label: string; - input: boolean; - tableView: boolean; - components: { - label: string; - mask: boolean; - tableView: boolean; - delimiter: boolean; - requireDecimal: boolean; - inputFormat: string; - key: string; - type: string; - input: boolean; - }[]; - attrs?: undefined; - content?: undefined; - refreshOnChange?: undefined; - } - | { - title: string; - collapsible: boolean; - key: string; - type: string; - label: string; - input: boolean; - tableView: boolean; - components: { - label: string; - mask: boolean; - tableView: boolean; - delimiter: boolean; - requireDecimal: boolean; - inputFormat: string; - validate: { - customMessage: string; - custom: string; - }; - key: string; - type: string; - input: boolean; - }[]; - attrs?: undefined; - content?: undefined; - refreshOnChange?: undefined; - } - )[]; - breadcrumbClickable?: undefined; - buttonSettings?: undefined; - scrollToTop?: undefined; - disableOnInvalid?: undefined; - } - | { - title: string; - collapsible: boolean; - key: string; - type: string; - label: string; - input: boolean; - tableView: boolean; - components: ( - | { - label: string; - attrs: { - attr: string; - value: string; - }[]; - content: string; - refreshOnChange: boolean; - key: string; - type: string; - input: boolean; - tableView: boolean; - reorder?: undefined; - addAnotherPosition?: undefined; - layoutFixed?: undefined; - enableRowGroups?: undefined; - initEmpty?: undefined; - defaultValue?: undefined; - components?: undefined; - title?: undefined; - tooltip?: undefined; - collapsible?: undefined; - } - | { - label: string; - reorder: boolean; - addAnotherPosition: string; - layoutFixed: boolean; - enableRowGroups: boolean; - initEmpty: boolean; - tableView: boolean; - defaultValue: {}[]; - key: string; - type: string; - input: boolean; - components: ( - | { - label: string; - mask: boolean; - tableView: boolean; - delimiter: boolean; - requireDecimal: boolean; - inputFormat: string; - key: string; - type: string; - input: boolean; - validate?: undefined; - errorLabel?: undefined; - } - | { - label: string; - mask: boolean; - tableView: boolean; - delimiter: boolean; - requireDecimal: boolean; - inputFormat: string; - validate: { - customMessage: string; - custom: string; - }; - errorLabel: string; - key: string; - type: string; - input: boolean; - } - )[]; - attrs?: undefined; - content?: undefined; - refreshOnChange?: undefined; - title?: undefined; - tooltip?: undefined; - collapsible?: undefined; - } - | { - title: string; - tooltip: string; - collapsible: boolean; - key: string; - type: string; - label: string; - input: boolean; - tableView: boolean; - components: { - label: string; - mask: boolean; - tableView: boolean; - delimiter: boolean; - requireDecimal: boolean; - inputFormat: string; - validate: { - customMessage: string; - custom: string; - }; - key: string; - type: string; - input: boolean; - }[]; - attrs?: undefined; - content?: undefined; - refreshOnChange?: undefined; - reorder?: undefined; - addAnotherPosition?: undefined; - layoutFixed?: undefined; - enableRowGroups?: undefined; - initEmpty?: undefined; - defaultValue?: undefined; - } - )[]; - breadcrumbClickable?: undefined; - buttonSettings?: undefined; - scrollToTop?: undefined; - disableOnInvalid?: undefined; - } - | { - title: string; - collapsible: boolean; - key: string; - type: string; - label: string; - input: boolean; - tableView: boolean; - components: ( - | { - label: string; - attrs: { - attr: string; - value: string; - }[]; - content: string; - refreshOnChange: boolean; - key: string; - type: string; - input: boolean; - tableView: boolean; - enableMinDateInput?: undefined; - datePicker?: undefined; - enableMaxDateInput?: undefined; - widget?: undefined; - } - | { - label: string; - tableView: boolean; - enableMinDateInput: boolean; - datePicker: { - disableWeekends: boolean; - disableWeekdays: boolean; - maxDate: string; - minDate: string; - }; - enableMaxDateInput: boolean; - key: string; - type: string; - input: boolean; - widget: { - type: string; - displayInTimezone: string; - locale: string; - useLocaleSettings: boolean; - allowInput: boolean; - mode: string; - enableTime: boolean; - noCalendar: boolean; - format: string; - hourIncrement: number; - minuteIncrement: number; - time_24hr: boolean; - minDate: string; - disableWeekends: boolean; - disableWeekdays: boolean; - maxDate: string; - }; - attrs?: undefined; - content?: undefined; - refreshOnChange?: undefined; - } - )[]; - breadcrumbClickable?: undefined; - buttonSettings?: undefined; - scrollToTop?: undefined; - disableOnInvalid?: undefined; - } - | { - type: string; - label: string; - key: string; - disableOnInvalid: boolean; - input: boolean; - tableView: boolean; - title?: undefined; - collapsible?: undefined; - components?: undefined; - breadcrumbClickable?: undefined; - buttonSettings?: undefined; - scrollToTop?: undefined; - } - )[]; - revisions: string; - _vid: number; - title: string; - display: string; - access: { - roles: string[]; - type: string; - }[]; - submissionAccess: never[]; - controller: string; - properties: {}; - settings: {}; - name: string; - path: string; - project: string; - created: string; - modified: string; - machineName: string; -}; -export declare const inlineembed: { - _id: string; - type: string; - tags: never[]; - owner: string; - components: ( - | { - html: string; - label: string; - refreshOnChange: boolean; - key: string; - type: string; - input: boolean; - tableView: boolean; - columns?: undefined; - hideOnChildrenHidden?: undefined; - } - | { - label: string; - columns: ( - | { - components: { - title: string; - collapsible: boolean; - key: string; - type: string; - label: string; - input: boolean; - tableView: boolean; - components: ( - | { - label: string; - defaultValue: string; - key: string; - type: string; - tableView: boolean; - input: boolean; - mask: boolean; - inputType: string; - inputFormat: string; - spellcheck: boolean; - hideOnChildrenHidden: boolean; - validate?: undefined; - widget?: undefined; - data?: undefined; - searchThreshold?: undefined; - title?: undefined; - collapsible?: undefined; - components?: undefined; - collapsed?: undefined; - } - | { - label: string; - tableView: boolean; - key: string; - type: string; - input: boolean; - mask: boolean; - inputType: string; - inputFormat: string; - spellcheck: boolean; - hideOnChildrenHidden: boolean; - defaultValue?: undefined; - validate?: undefined; - widget?: undefined; - data?: undefined; - searchThreshold?: undefined; - title?: undefined; - collapsible?: undefined; - components?: undefined; - collapsed?: undefined; - } - | { - label: string; - tableView: boolean; - validate: { - required: boolean; - }; - key: string; - type: string; - input: boolean; - defaultValue: string; - hideOnChildrenHidden: boolean; - mask?: undefined; - inputType?: undefined; - inputFormat?: undefined; - spellcheck?: undefined; - widget?: undefined; - data?: undefined; - searchThreshold?: undefined; - title?: undefined; - collapsible?: undefined; - components?: undefined; - collapsed?: undefined; - } - | { - label: string; - widget: string; - tableView: boolean; - data: { - values: { - label: string; - value: string; - }[]; - }; - key: string; - type: string; - input: boolean; - searchThreshold: number; - hideOnChildrenHidden: boolean; - defaultValue?: undefined; - mask?: undefined; - inputType?: undefined; - inputFormat?: undefined; - spellcheck?: undefined; - validate?: undefined; - title?: undefined; - collapsible?: undefined; - components?: undefined; - collapsed?: undefined; - } - | { - title: string; - collapsible: boolean; - key: string; - type: string; - label: string; - input: boolean; - tableView: boolean; - components: ( - | { - label: string; - tableView: boolean; - key: string; - type: string; - input: boolean; - defaultValue?: undefined; - calculateValue?: undefined; - editor?: undefined; - autoExpand?: undefined; - as?: undefined; - } - | { - label: string; - tableView: boolean; - defaultValue: boolean; - calculateValue: string; - key: string; - type: string; - input: boolean; - editor?: undefined; - autoExpand?: undefined; - as?: undefined; - } - | { - label: string; - tableView: boolean; - key: string; - type: string; - input: boolean; - defaultValue: boolean; - calculateValue?: undefined; - editor?: undefined; - autoExpand?: undefined; - as?: undefined; - } - | { - label: string; - editor: string; - autoExpand: boolean; - tableView: boolean; - key: string; - type: string; - as: string; - input: boolean; - defaultValue?: undefined; - calculateValue?: undefined; - } - | { - input: boolean; - key: string; - tableView: boolean; - label: string; - type: string; - editor: string; - as: string; - defaultValue?: undefined; - calculateValue?: undefined; - autoExpand?: undefined; - } - )[]; - collapsed: boolean; - hideOnChildrenHidden: boolean; - defaultValue?: undefined; - mask?: undefined; - inputType?: undefined; - inputFormat?: undefined; - spellcheck?: undefined; - validate?: undefined; - widget?: undefined; - data?: undefined; - searchThreshold?: undefined; - } - )[]; - hideOnChildrenHidden: boolean; - }[]; - width: number; - offset: number; - push: number; - pull: number; - size: string; - currentWidth: number; - } - | { - components: { - title: string; - collapsible: boolean; - key: string; - type: string; - label: string; - input: boolean; - tableView: boolean; - components: ( - | { - label: string; - tag: string; - attrs: { - attr: string; - value: string; - }[]; - content: string; - refreshOnChange: boolean; - key: string; - type: string; - input: boolean; - tableView: boolean; - action?: undefined; - showValidations?: undefined; - theme?: undefined; - block?: undefined; - leftIcon?: undefined; - custom?: undefined; - hideOnChildrenHidden?: undefined; - } - | { - label: string; - action: string; - showValidations: boolean; - theme: string; - block: boolean; - leftIcon: string; - tableView: boolean; - key: string; - type: string; - custom: string; - input: boolean; - hideOnChildrenHidden: boolean; - tag?: undefined; - attrs?: undefined; - content?: undefined; - refreshOnChange?: undefined; - } - )[]; - hideOnChildrenHidden: boolean; - }[]; - width: number; - offset: number; - push: number; - pull: number; - size: string; - currentWidth: number; - } - )[]; - hideOnChildrenHidden: boolean; - key: string; - type: string; - input: boolean; - tableView: boolean; - html?: undefined; - refreshOnChange?: undefined; - } - )[]; - revisions: string; - _vid: number; - title: string; - display: string; - access: { - roles: string[]; - type: string; - }[]; - submissionAccess: never[]; - controller: string; - properties: {}; - settings: {}; - name: string; - path: string; - project: string; - created: string; - modified: string; - machineName: string; -}; -export declare const customerLoad: { - _id: string; - title: string; - display: string; - type: string; - components: ( - | { - input: boolean; - tableView: boolean; - inputType: string; - label: string; - key: string; - validate: { - required: boolean; - min: number; - max: number; - }; - type: string; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - type: string; - inputType?: undefined; - validate?: undefined; - } - )[]; - access: { - roles: string[]; - type: string; - }[]; - submissionAccess: { - roles: never[]; - type: string; - }[]; - settings: {}; - name: string; - path: string; - owner: string; - project: string; - tags: never[]; - created: string; - revisions: string; - _vid: number; - modified: string; - machineName: string; -}; -export declare const kitchenSink: { - _id: string; - type: string; - tags: never[]; - owner: string; - components: ( - | { - label: string; - title: string; - collapsible: boolean; - mask: boolean; - tableView: boolean; - alwaysEnabled: boolean; - type: string; - input: boolean; - key: string; - components: ( - | { - label: string; - columns: ( - | { - components: { - label: string; - placeholder: string; - tableView: boolean; - alwaysEnabled: boolean; - type: string; - input: boolean; - key: string; - validate: { - required: boolean; - }; - widget: { - type: string; - format: string; - dateFormat: string; - saveAs: string; - }; - reorder: boolean; - hideOnChildrenHidden: boolean; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - }[]; - width: number; - offset: number; - push: number; - pull: number; - type: string; - input: boolean; - hideOnChildrenHidden: boolean; - key: string; - tableView: boolean; - label: string; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - dataGridLabel: boolean; - labelPosition: string; - labelWidth: number; - labelMargin: number; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - allowCalculateOverride: boolean; - widget: null; - refreshOn: string; - clearOnRefresh: boolean; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - id: string; - size: string; - currentWidth: number; - } - | { - components: { - label: string; - placeholder: string; - tableView: boolean; - alwaysEnabled: boolean; - type: string; - input: boolean; - key: string; - widget: { - type: string; - format: string; - dateFormat: string; - saveAs: string; - }; - reorder: boolean; - hideOnChildrenHidden: boolean; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - }[]; - width: number; - offset: number; - push: number; - pull: number; - type: string; - input: boolean; - hideOnChildrenHidden: boolean; - key: string; - tableView: boolean; - label: string; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - dataGridLabel: boolean; - labelPosition: string; - labelWidth: number; - labelMargin: number; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - allowCalculateOverride: boolean; - widget: null; - refreshOn: string; - clearOnRefresh: boolean; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - id: string; - size: string; - currentWidth: number; - } - | { - width: number; - offset: number; - push: number; - pull: number; - type: string; - input: boolean; - hideOnChildrenHidden: boolean; - key: string; - tableView: boolean; - label: string; - components: { - label: string; - placeholder: string; - description: string; - tooltip: string; - tableView: boolean; - alwaysEnabled: boolean; - type: string; - input: boolean; - key: string; - validate: { - required: boolean; - }; - widget: { - type: string; - format: string; - dateFormat: string; - saveAs: string; - }; - reorder: boolean; - hideOnChildrenHidden: boolean; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - }[]; - placeholder: string; - prefix: string; - customClass: string; - suffix: string; - multiple: boolean; - defaultValue: null; - protected: boolean; - unique: boolean; - persistent: boolean; - hidden: boolean; - clearOnHide: boolean; - dataGridLabel: boolean; - labelPosition: string; - labelWidth: number; - labelMargin: number; - description: string; - errorLabel: string; - tooltip: string; - hideLabel: boolean; - tabindex: string; - disabled: boolean; - autofocus: boolean; - dbIndex: boolean; - customDefaultValue: string; - calculateValue: string; - allowCalculateOverride: boolean; - widget: null; - refreshOn: string; - clearOnRefresh: boolean; - validateOn: string; - validate: { - required: boolean; - custom: string; - customPrivate: boolean; - }; - conditional: { - show: null; - when: null; - eq: string; - }; - id: string; - size: string; - currentWidth: number; - } - )[]; - mask: boolean; - tableView: boolean; - alwaysEnabled: boolean; - type: string; - input: boolean; - key: string; - reorder: boolean; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - hideOnChildrenHidden: boolean; - widget?: undefined; - inputMasks?: undefined; - title?: undefined; - theme?: undefined; - components?: undefined; - collapsible?: undefined; - collapsed?: undefined; - editor?: undefined; - wysiwyg?: undefined; - rows?: undefined; - defaultValue?: undefined; - inputFormat?: undefined; - autoExpand?: undefined; - isUploadEnabled?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - type: string; - labelWidth: number; - labelMargin: number; - widget: { - format: string; - dateFormat: string; - saveAs: string; - }; - clearOnRefresh: boolean; - alwaysEnabled: boolean; - columns?: undefined; - mask?: undefined; - reorder?: undefined; - hideOnChildrenHidden?: undefined; - inputMasks?: undefined; - title?: undefined; - theme?: undefined; - components?: undefined; - collapsible?: undefined; - collapsed?: undefined; - editor?: undefined; - wysiwyg?: undefined; - rows?: undefined; - defaultValue?: undefined; - inputFormat?: undefined; - autoExpand?: undefined; - isUploadEnabled?: undefined; - } - | { - label: string; - inputMasks: { - label: string; - mask: string; - }[]; - alwaysEnabled: boolean; - tableView: boolean; - key: string; - type: string; - input: boolean; - columns?: undefined; - mask?: undefined; - reorder?: undefined; - labelWidth?: undefined; - labelMargin?: undefined; - clearOnRefresh?: undefined; - hideOnChildrenHidden?: undefined; - widget?: undefined; - title?: undefined; - theme?: undefined; - components?: undefined; - collapsible?: undefined; - collapsed?: undefined; - editor?: undefined; - wysiwyg?: undefined; - rows?: undefined; - defaultValue?: undefined; - inputFormat?: undefined; - autoExpand?: undefined; - isUploadEnabled?: undefined; - } - | { - key: string; - input: boolean; - title: string; - theme: string; - tableView: boolean; - components: ( - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - type: string; - labelWidth: number; - labelMargin: number; - widget: { - format: string; - dateFormat: string; - saveAs: string; - type?: undefined; - displayInTimezone?: undefined; - locale?: undefined; - useLocaleSettings?: undefined; - allowInput?: undefined; - mode?: undefined; - enableTime?: undefined; - noCalendar?: undefined; - hourIncrement?: undefined; - minuteIncrement?: undefined; - time_24hr?: undefined; - minDate?: undefined; - maxDate?: undefined; - }; - clearOnRefresh: boolean; - alwaysEnabled: boolean; - inputType?: undefined; - protected?: undefined; - inputMask?: undefined; - reorder?: undefined; - datePicker?: undefined; - suffix?: undefined; - defaultValue?: undefined; - delimiter?: undefined; - decimalLimit?: undefined; - requireDecimal?: undefined; - tooltip?: undefined; - description?: undefined; - lockKey?: undefined; - prefix?: undefined; - data?: undefined; - valueProperty?: undefined; - multiple?: undefined; - inputFormat?: undefined; - values?: undefined; - optionsLabelPosition?: undefined; - inline?: undefined; - } - | { - input: boolean; - tableView: boolean; - inputType: string; - label: string; - key: string; - protected: boolean; - type: string; - labelWidth: number; - labelMargin: number; - widget: { - format: string; - dateFormat: string; - saveAs: string; - type?: undefined; - displayInTimezone?: undefined; - locale?: undefined; - useLocaleSettings?: undefined; - allowInput?: undefined; - mode?: undefined; - enableTime?: undefined; - noCalendar?: undefined; - hourIncrement?: undefined; - minuteIncrement?: undefined; - time_24hr?: undefined; - minDate?: undefined; - maxDate?: undefined; - }; - clearOnRefresh: boolean; - alwaysEnabled: boolean; - inputMask?: undefined; - reorder?: undefined; - datePicker?: undefined; - suffix?: undefined; - defaultValue?: undefined; - delimiter?: undefined; - decimalLimit?: undefined; - requireDecimal?: undefined; - tooltip?: undefined; - description?: undefined; - lockKey?: undefined; - prefix?: undefined; - data?: undefined; - valueProperty?: undefined; - multiple?: undefined; - inputFormat?: undefined; - values?: undefined; - optionsLabelPosition?: undefined; - inline?: undefined; - } - | { - label: string; - inputMask: string; - tableView: boolean; - alwaysEnabled: boolean; - type: string; - input: boolean; - key: string; - widget: { - type: string; - format: string; - dateFormat: string; - saveAs: string; - displayInTimezone?: undefined; - locale?: undefined; - useLocaleSettings?: undefined; - allowInput?: undefined; - mode?: undefined; - enableTime?: undefined; - noCalendar?: undefined; - hourIncrement?: undefined; - minuteIncrement?: undefined; - time_24hr?: undefined; - minDate?: undefined; - maxDate?: undefined; - }; - reorder: boolean; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - inputType?: undefined; - protected?: undefined; - datePicker?: undefined; - suffix?: undefined; - defaultValue?: undefined; - delimiter?: undefined; - decimalLimit?: undefined; - requireDecimal?: undefined; - tooltip?: undefined; - description?: undefined; - lockKey?: undefined; - prefix?: undefined; - data?: undefined; - valueProperty?: undefined; - multiple?: undefined; - inputFormat?: undefined; - values?: undefined; - optionsLabelPosition?: undefined; - inline?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - datePicker: { - datepickerMode: string; - }; - type: string; - suffix: string; - widget: { - type: string; - displayInTimezone: string; - locale: string; - useLocaleSettings: boolean; - allowInput: boolean; - mode: string; - enableTime: boolean; - noCalendar: boolean; - format: string; - hourIncrement: number; - minuteIncrement: number; - time_24hr: boolean; - minDate: null; - maxDate: null; - dateFormat?: undefined; - saveAs?: undefined; - }; - defaultValue: null; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - alwaysEnabled: boolean; - inputType?: undefined; - protected?: undefined; - inputMask?: undefined; - reorder?: undefined; - delimiter?: undefined; - decimalLimit?: undefined; - requireDecimal?: undefined; - tooltip?: undefined; - description?: undefined; - lockKey?: undefined; - prefix?: undefined; - data?: undefined; - valueProperty?: undefined; - multiple?: undefined; - inputFormat?: undefined; - values?: undefined; - optionsLabelPosition?: undefined; - inline?: undefined; - } - | { - input: boolean; - tableView: boolean; - inputType: string; - label: string; - key: string; - suffix: string; - delimiter: boolean; - decimalLimit: number; - requireDecimal: boolean; - type: string; - tooltip: string; - description: string; - lockKey: boolean; - labelWidth: number; - labelMargin: number; - widget: null; - clearOnRefresh: boolean; - alwaysEnabled: boolean; - protected?: undefined; - inputMask?: undefined; - reorder?: undefined; - datePicker?: undefined; - defaultValue?: undefined; - prefix?: undefined; - data?: undefined; - valueProperty?: undefined; - multiple?: undefined; - inputFormat?: undefined; - values?: undefined; - optionsLabelPosition?: undefined; - inline?: undefined; - } - | { - input: boolean; - tableView: boolean; - inputType: string; - label: string; - key: string; - prefix: string; - type: string; - labelWidth: number; - labelMargin: number; - widget: null; - clearOnRefresh: boolean; - alwaysEnabled: boolean; - protected?: undefined; - inputMask?: undefined; - reorder?: undefined; - datePicker?: undefined; - suffix?: undefined; - defaultValue?: undefined; - delimiter?: undefined; - decimalLimit?: undefined; - requireDecimal?: undefined; - tooltip?: undefined; - description?: undefined; - lockKey?: undefined; - data?: undefined; - valueProperty?: undefined; - multiple?: undefined; - inputFormat?: undefined; - values?: undefined; - optionsLabelPosition?: undefined; - inline?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - data: { - values: { - value: string; - label: string; - }[]; - }; - valueProperty: string; - defaultValue: string; - type: string; - labelWidth: number; - labelMargin: number; - alwaysEnabled: boolean; - widget?: undefined; - clearOnRefresh?: undefined; - inputType?: undefined; - protected?: undefined; - inputMask?: undefined; - reorder?: undefined; - datePicker?: undefined; - suffix?: undefined; - delimiter?: undefined; - decimalLimit?: undefined; - requireDecimal?: undefined; - tooltip?: undefined; - description?: undefined; - lockKey?: undefined; - prefix?: undefined; - multiple?: undefined; - inputFormat?: undefined; - values?: undefined; - optionsLabelPosition?: undefined; - inline?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - data: { - values: { - value: string; - label: string; - }[]; - }; - valueProperty: string; - multiple: boolean; - type: string; - labelWidth: number; - labelMargin: number; - alwaysEnabled: boolean; - widget?: undefined; - clearOnRefresh?: undefined; - inputType?: undefined; - protected?: undefined; - inputMask?: undefined; - reorder?: undefined; - datePicker?: undefined; - suffix?: undefined; - defaultValue?: undefined; - delimiter?: undefined; - decimalLimit?: undefined; - requireDecimal?: undefined; - tooltip?: undefined; - description?: undefined; - lockKey?: undefined; - prefix?: undefined; - inputFormat?: undefined; - values?: undefined; - optionsLabelPosition?: undefined; - inline?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - type: string; - inputFormat: string; - labelWidth?: undefined; - labelMargin?: undefined; - widget?: undefined; - clearOnRefresh?: undefined; - alwaysEnabled?: undefined; - inputType?: undefined; - protected?: undefined; - inputMask?: undefined; - reorder?: undefined; - datePicker?: undefined; - suffix?: undefined; - defaultValue?: undefined; - delimiter?: undefined; - decimalLimit?: undefined; - requireDecimal?: undefined; - tooltip?: undefined; - description?: undefined; - lockKey?: undefined; - prefix?: undefined; - data?: undefined; - valueProperty?: undefined; - multiple?: undefined; - values?: undefined; - optionsLabelPosition?: undefined; - inline?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - values: { - value: string; - label: string; - shortcut: string; - }[]; - type: string; - optionsLabelPosition: string; - tooltip: string; - inline: boolean; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - alwaysEnabled: boolean; - widget?: undefined; - inputType?: undefined; - protected?: undefined; - inputMask?: undefined; - reorder?: undefined; - datePicker?: undefined; - suffix?: undefined; - defaultValue?: undefined; - delimiter?: undefined; - decimalLimit?: undefined; - requireDecimal?: undefined; - description?: undefined; - lockKey?: undefined; - prefix?: undefined; - data?: undefined; - valueProperty?: undefined; - multiple?: undefined; - inputFormat?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - values: { - value: string; - label: string; - shortcut: string; - }[]; - type: string; - optionsLabelPosition: string; - inputType: string; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - alwaysEnabled: boolean; - widget?: undefined; - protected?: undefined; - inputMask?: undefined; - reorder?: undefined; - datePicker?: undefined; - suffix?: undefined; - defaultValue?: undefined; - delimiter?: undefined; - decimalLimit?: undefined; - requireDecimal?: undefined; - tooltip?: undefined; - description?: undefined; - lockKey?: undefined; - prefix?: undefined; - data?: undefined; - valueProperty?: undefined; - multiple?: undefined; - inputFormat?: undefined; - inline?: undefined; - } - )[]; - type: string; - collapsible: boolean; - collapsed: boolean; - label: string; - columns?: undefined; - mask?: undefined; - alwaysEnabled?: undefined; - reorder?: undefined; - labelWidth?: undefined; - labelMargin?: undefined; - clearOnRefresh?: undefined; - hideOnChildrenHidden?: undefined; - widget?: undefined; - inputMasks?: undefined; - editor?: undefined; - wysiwyg?: undefined; - rows?: undefined; - defaultValue?: undefined; - inputFormat?: undefined; - autoExpand?: undefined; - isUploadEnabled?: undefined; - } - | { - label: string; - editor: string; - tableView: boolean; - alwaysEnabled: boolean; - wysiwyg: { - theme: string; - placeholder: string; - modules: { - clipboard: { - matchVisual: boolean; - }; - toolbar: ( - | { - size: (string | boolean)[]; - }[] - | { - header: (number | boolean)[]; - }[] - | { - font: never[]; - }[] - | ( - | string - | { - script: string; - } - )[] - | ( - | { - color: never[]; - background?: undefined; - } - | { - background: never[]; - color?: undefined; - } - )[] - | ( - | { - list: string; - indent?: undefined; - align?: undefined; - } - | { - indent: string; - list?: undefined; - align?: undefined; - } - | { - align: never[]; - list?: undefined; - indent?: undefined; - } - )[] - )[]; - }; - rows: number; - base64Upload: boolean; - image: { - toolbar: string[]; - styles: string[]; - }; - disableNativeSpellChecker: boolean; - mediaEmbed: { - previewsInData: boolean; - }; - }; - rows: number; - type: string; - input: boolean; - key: string; - defaultValue: string; - inputFormat: string; - autoExpand: boolean; - isUploadEnabled: boolean; - reorder: boolean; - widget: { - format: string; - dateFormat: string; - saveAs: string; - }; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - columns?: undefined; - mask?: undefined; - hideOnChildrenHidden?: undefined; - inputMasks?: undefined; - title?: undefined; - theme?: undefined; - components?: undefined; - collapsible?: undefined; - collapsed?: undefined; - } - )[]; - collapsed: boolean; - reorder: boolean; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - path: string; - templates?: undefined; - removeRow?: undefined; - questions?: undefined; - values?: undefined; - clearOnHide?: undefined; - legend?: undefined; - hideLabel?: undefined; - disableOnInvalid?: undefined; - widget?: undefined; - } - | { - label: string; - reorder: boolean; - mask: boolean; - tableView: boolean; - alwaysEnabled: boolean; - type: string; - input: boolean; - key: string; - components: ( - | { - label: string; - tableView: boolean; - alwaysEnabled: boolean; - type: string; - input: boolean; - key: string; - widget: { - type: string; - format: string; - dateFormat: string; - saveAs: string; - }; - reorder: boolean; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - hideInputLabels?: undefined; - inputsLabelPosition?: undefined; - fields?: undefined; - useLocaleSettings?: undefined; - mask?: undefined; - } - | { - label: string; - hideInputLabels: boolean; - inputsLabelPosition: string; - fields: { - day: { - hide: boolean; - }; - month: { - hide: boolean; - }; - year: { - hide: boolean; - }; - }; - useLocaleSettings: boolean; - mask: boolean; - tableView: boolean; - alwaysEnabled: boolean; - type: string; - input: boolean; - key: string; - reorder: boolean; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - widget?: undefined; - } - )[]; - templates: { - header: string; - row: string; - }; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - removeRow: string; - title?: undefined; - collapsible?: undefined; - collapsed?: undefined; - path?: undefined; - questions?: undefined; - values?: undefined; - clearOnHide?: undefined; - legend?: undefined; - hideLabel?: undefined; - disableOnInvalid?: undefined; - widget?: undefined; - } - | { - label: string; - alwaysEnabled: boolean; - tableView: boolean; - questions: { - label: string; - value: string; - }[]; - values: { - label: string; - value: string; - }[]; - key: string; - type: string; - input: boolean; - title?: undefined; - collapsible?: undefined; - mask?: undefined; - components?: undefined; - collapsed?: undefined; - reorder?: undefined; - labelWidth?: undefined; - labelMargin?: undefined; - clearOnRefresh?: undefined; - path?: undefined; - templates?: undefined; - removeRow?: undefined; - clearOnHide?: undefined; - legend?: undefined; - hideLabel?: undefined; - disableOnInvalid?: undefined; - widget?: undefined; - } - | { - label: string; - alwaysEnabled: boolean; - tableView: boolean; - key: string; - type: string; - input: boolean; - components: { - label: string; - reorder: boolean; - addAnotherPosition: string; - defaultOpen: boolean; - layoutFixed: boolean; - enableRowGroups: boolean; - alwaysEnabled: boolean; - tableView: boolean; - key: string; - type: string; - input: boolean; - components: { - label: string; - widget: { - i18n: { - lng: string; - resources: { - en: { - translation: { - complete: string; - error: string; - required: string; - pattern: string; - minLength: string; - maxLength: string; - minWords: string; - maxWords: string; - min: string; - max: string; - minSelectedCount: string; - maxSelectedCount: string; - maxDate: string; - minDate: string; - invalid_email: string; - invalid_url: string; - invalid_regex: string; - invalid_date: string; - invalid_day: string; - mask: string; - stripe: string; - month: string; - day: string; - year: string; - january: string; - february: string; - march: string; - april: string; - may: string; - june: string; - july: string; - august: string; - september: string; - october: string; - november: string; - december: string; - next: string; - previous: string; - cancel: string; - submit: string; - }; - }; - }; - }; - language: string; - format: string; - dateFormat: string; - saveAs: string; - }; - alwaysEnabled: boolean; - tableView: boolean; - key: string; - type: string; - input: boolean; - inDataGrid: boolean; - row: string; - }[]; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - }[]; - path: string; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - title?: undefined; - collapsible?: undefined; - mask?: undefined; - collapsed?: undefined; - reorder?: undefined; - templates?: undefined; - removeRow?: undefined; - questions?: undefined; - values?: undefined; - clearOnHide?: undefined; - legend?: undefined; - hideLabel?: undefined; - disableOnInvalid?: undefined; - widget?: undefined; - } - | { - title: string; - collapsible: boolean; - alwaysEnabled: boolean; - tableView: boolean; - key: string; - type: string; - input: boolean; - label: string; - components: { - label: string; - alwaysEnabled: boolean; - tableView: boolean; - key: string; - type: string; - input: boolean; - components: { - label: string; - widget: { - i18n: { - lng: string; - resources: { - en: { - translation: { - complete: string; - error: string; - required: string; - pattern: string; - minLength: string; - maxLength: string; - minWords: string; - maxWords: string; - min: string; - max: string; - minSelectedCount: string; - maxSelectedCount: string; - maxDate: string; - minDate: string; - invalid_email: string; - invalid_url: string; - invalid_regex: string; - invalid_date: string; - invalid_day: string; - mask: string; - stripe: string; - month: string; - day: string; - year: string; - january: string; - february: string; - march: string; - april: string; - may: string; - june: string; - july: string; - august: string; - september: string; - october: string; - november: string; - december: string; - next: string; - previous: string; - cancel: string; - submit: string; - }; - }; - }; - }; - language: string; - format: string; - dateFormat: string; - saveAs: string; - }; - alwaysEnabled: boolean; - tableView: boolean; - key: string; - type: string; - input: boolean; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - }[]; - path: string; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - }[]; - path: string; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - mask?: undefined; - collapsed?: undefined; - reorder?: undefined; - templates?: undefined; - removeRow?: undefined; - questions?: undefined; - values?: undefined; - clearOnHide?: undefined; - legend?: undefined; - hideLabel?: undefined; - disableOnInvalid?: undefined; - widget?: undefined; - } - | { - label: string; - components: { - label: string; - key: string; - components: ( - | { - label: string; - tableView: boolean; - alwaysEnabled: boolean; - type: string; - input: boolean; - key: string; - tab: number; - widget: { - type: string; - format: string; - dateFormat: string; - saveAs: string; - }; - reorder: boolean; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - } - | { - label: string; - alwaysEnabled: boolean; - tableView: boolean; - key: string; - type: string; - input: boolean; - tab?: undefined; - widget?: undefined; - reorder?: undefined; - labelWidth?: undefined; - labelMargin?: undefined; - clearOnRefresh?: undefined; - } - )[]; - }[]; - mask: boolean; - tableView: boolean; - alwaysEnabled: boolean; - type: string; - input: boolean; - key: string; - reorder: boolean; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - path: string; - title?: undefined; - collapsible?: undefined; - collapsed?: undefined; - templates?: undefined; - removeRow?: undefined; - questions?: undefined; - values?: undefined; - clearOnHide?: undefined; - legend?: undefined; - hideLabel?: undefined; - disableOnInvalid?: undefined; - widget?: undefined; - } - | { - clearOnHide: boolean; - key: string; - input: boolean; - tableView: boolean; - legend: string; - components: ( - | { - key: string; - input: boolean; - html: string; - type: string; - tableView: boolean; - label: string; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - alwaysEnabled: boolean; - dataGridLabel?: undefined; - defaultValue?: undefined; - tooltip?: undefined; - hideLabel?: undefined; - widget?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - dataGridLabel: boolean; - key: string; - defaultValue: boolean; - type: string; - tooltip: string; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - alwaysEnabled: boolean; - html?: undefined; - hideLabel?: undefined; - widget?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - type: string; - hideLabel: boolean; - labelWidth: number; - labelMargin: number; - widget: null; - clearOnRefresh: boolean; - alwaysEnabled: boolean; - html?: undefined; - dataGridLabel?: undefined; - defaultValue?: undefined; - tooltip?: undefined; - } - )[]; - type: string; - hideLabel: boolean; - label: string; - labelWidth: number; - labelMargin: number; - clearOnRefresh: boolean; - alwaysEnabled: boolean; - title?: undefined; - collapsible?: undefined; - mask?: undefined; - collapsed?: undefined; - reorder?: undefined; - path?: undefined; - templates?: undefined; - removeRow?: undefined; - questions?: undefined; - values?: undefined; - disableOnInvalid?: undefined; - widget?: undefined; - } - | { - type: string; - label: string; - key: string; - disableOnInvalid: boolean; - input: boolean; - tableView: boolean; - alwaysEnabled: boolean; - labelWidth: number; - labelMargin: number; - widget: null; - clearOnRefresh: boolean; - title?: undefined; - collapsible?: undefined; - mask?: undefined; - components?: undefined; - collapsed?: undefined; - reorder?: undefined; - path?: undefined; - templates?: undefined; - removeRow?: undefined; - questions?: undefined; - values?: undefined; - clearOnHide?: undefined; - legend?: undefined; - hideLabel?: undefined; - } - )[]; - revisions: string; - _vid: number; - title: string; - display: string; - access: { - roles: string[]; - type: string; - }[]; - submissionAccess: { - roles: string[]; - type: string; - }[]; - settings: {}; - properties: {}; - name: string; - path: string; - project: string; - created: string; - modified: string; - machineName: string; -}; -export declare const otherForm: { - _id: string; - machineName: string; - modified: string; - title: string; - display: string; - name: string; - path: string; - project: string; - created: string; - components: ( - | { - key: string; - input: boolean; - html: string; - type: string; - tableView: boolean; - label: string; - mask?: undefined; - spellcheck?: undefined; - disabled?: undefined; - delimiter?: undefined; - requireDecimal?: undefined; - inputFormat?: undefined; - customDefaultValue?: undefined; - calculateValue?: undefined; - inputType?: undefined; - values?: undefined; - data?: undefined; - lockKey?: undefined; - } - | { - label: string; - mask: boolean; - spellcheck: boolean; - disabled: boolean; - tableView: boolean; - delimiter: boolean; - requireDecimal: boolean; - inputFormat: string; - customDefaultValue: string; - calculateValue: { - '+': { - var: string; - }[]; - if?: undefined; - }; - key: string; - type: string; - inputType: string; - input: boolean; - html?: undefined; - values?: undefined; - data?: undefined; - lockKey?: undefined; - } - | { - disabled: boolean; - type: string; - key: string; - label: string; - inputType: string; - tableView: boolean; - input: boolean; - calculateValue: { - if: ( - | number - | { - '==': ( - | string - | { - var: string; - } - )[]; - } - )[]; - '+'?: undefined; - }; - html?: undefined; - mask?: undefined; - spellcheck?: undefined; - delimiter?: undefined; - requireDecimal?: undefined; - inputFormat?: undefined; - customDefaultValue?: undefined; - values?: undefined; - data?: undefined; - lockKey?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - values: { - value: string; - label: string; - }[]; - type: string; - html?: undefined; - mask?: undefined; - spellcheck?: undefined; - disabled?: undefined; - delimiter?: undefined; - requireDecimal?: undefined; - inputFormat?: undefined; - customDefaultValue?: undefined; - calculateValue?: undefined; - inputType?: undefined; - data?: undefined; - lockKey?: undefined; - } - | { - input: boolean; - tableView: boolean; - label: string; - key: string; - data: { - values: { - value: string; - label: string; - }[]; - }; - type: string; - lockKey: boolean; - html?: undefined; - mask?: undefined; - spellcheck?: undefined; - disabled?: undefined; - delimiter?: undefined; - requireDecimal?: undefined; - inputFormat?: undefined; - customDefaultValue?: undefined; - calculateValue?: undefined; - inputType?: undefined; - values?: undefined; - } - | { - input: boolean; - label: string; - tableView: boolean; - key: string; - type: string; - html?: undefined; - mask?: undefined; - spellcheck?: undefined; - disabled?: undefined; - delimiter?: undefined; - requireDecimal?: undefined; - inputFormat?: undefined; - customDefaultValue?: undefined; - calculateValue?: undefined; - inputType?: undefined; - values?: undefined; - data?: undefined; - lockKey?: undefined; - } - )[]; - owner: string; - submissionAccess: { - roles: string[]; - type: string; - }[]; - access: { - roles: string[]; - type: string; - }[]; - tags: never[]; - type: string; - revisions: string; - _vid: number; - settings: {}; -}; -export declare const simpleNestedForm: { - display: string; - components: ( - | { - collapsible: boolean; - key: string; - type: string; - label: string; - input: boolean; - tableView: boolean; - components: ( - | { - label: string; - reorder: boolean; - addAnotherPosition: string; - layoutFixed: boolean; - enableRowGroups: boolean; - initEmpty: boolean; - tableView: boolean; - defaultValue: {}[]; - key: string; - type: string; - input: boolean; - components: ( - | { - label: string; - applyMaskOn: string; - tableView: boolean; - validate: { - required: boolean; - maxLength?: undefined; - pattern?: undefined; - }; - key: string; - type: string; - input: boolean; - } - | { - label: string; - applyMaskOn: string; - tableView: boolean; - validate: { - maxLength: number; - required?: undefined; - pattern?: undefined; - }; - key: string; - type: string; - input: boolean; - } - | { - label: string; - applyMaskOn: string; - tableView: boolean; - validate: { - pattern: string; - required?: undefined; - maxLength?: undefined; - }; - key: string; - type: string; - input: boolean; - } - )[]; - applyMaskOn?: undefined; - validate?: undefined; - } - | { - label: string; - applyMaskOn: string; - tableView: boolean; - validate: { - pattern: string; - minLength: number; - }; - key: string; - type: string; - input: boolean; - reorder?: undefined; - addAnotherPosition?: undefined; - layoutFixed?: undefined; - enableRowGroups?: undefined; - initEmpty?: undefined; - defaultValue?: undefined; - components?: undefined; - } - )[]; - disableOnInvalid?: undefined; - } - | { - type: string; - label: string; - key: string; - disableOnInvalid: boolean; - input: boolean; - tableView: boolean; - collapsible?: undefined; - components?: undefined; - } - )[]; -}; diff --git a/src/process/validation/rules/__tests__/fixtures/forms.js b/src/process/validation/rules/__tests__/fixtures/forms.js deleted file mode 100644 index 7ee58662..00000000 --- a/src/process/validation/rules/__tests__/fixtures/forms.js +++ /dev/null @@ -1,5946 +0,0 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); -exports.simpleNestedForm = - exports.otherForm = - exports.kitchenSink = - exports.customerLoad = - exports.inlineembed = - exports.validationRulesNyHealth = - exports.inlineEmbedFormPortal = - exports.wizard = - exports.simpleForm = - exports.example = - exports.w4 = - void 0; -exports.w4 = { - _id: '5994b43413a5f60007084c9f', - machineName: 'examples:w4', - modified: '2023-02-13T18:59:11.166Z', - title: 'W4', - display: 'pdf', - settings: { - pdf: { - id: '1ec0f8ee-6685-5d98-a847-26f67b67d6f0', - src: 'https://files.form.io/pdf/5692b91fd1028f01000407e3/file/1ec0f8ee-6685-5d98-a847-26f67b67d6f0', - }, - }, - name: 'w4', - path: 'w4', - project: '5692b91fd1028f01000407e3', - created: '2017-08-16T21:08:04.689Z', - components: [ - { - input: true, - tableView: true, - label: 'Office Code', - key: 'officeCode', - type: 'textfield', - overlay: { width: 121, height: 21, left: 656.344, top: 1319, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e279pgyh', - }, - { - input: true, - tableView: true, - label: 'Employers Name and Address', - key: 'employersName', - type: 'textfield', - overlay: { - width: 570, - height: 21, - left: 79.34379999999999, - top: 1320, - page: 1, - style: '', - }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'ebh0ey', - }, - { - input: true, - tableView: true, - label: 'date', - key: 'date', - datePicker: { - datepickerMode: 'day', - showWeeks: true, - startingDay: 0, - initDate: '', - minMode: 'day', - maxMode: 'year', - yearRows: 4, - yearColumns: 5, - minDate: null, - maxDate: null, - }, - type: 'datetime', - overlay: { width: 176, height: 22, left: 842.344, top: 1275, page: 1, style: '' }, - widget: { - type: 'calendar', - displayInTimezone: 'viewer', - submissionTimezone: 'Europe/Paris', - locale: 'en', - useLocaleSettings: false, - allowInput: true, - mode: 'single', - enableTime: true, - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - hourIncrement: 1, - minuteIncrement: 1, - time_24hr: false, - minDate: null, - maxDate: null, - }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: '', - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - format: 'yyyy-MM-dd hh:mm a', - useLocaleSettings: false, - allowInput: true, - enableDate: true, - enableTime: true, - defaultDate: '', - displayInTimezone: 'viewer', - timezone: '', - datepickerMode: 'day', - timePicker: { - hourStep: 1, - minuteStep: 1, - showMeridian: true, - readonlyInput: false, - mousewheel: true, - arrowkeys: true, - }, - customOptions: {}, - id: 'e38qzkb', - }, - { - input: true, - tableView: true, - label: 'Signature', - key: 'signature', - type: 'signature', - overlay: { width: 437, height: 41, left: 347.344, top: 1257, page: 1, style: '' }, - hideLabel: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - footer: 'Sign above', - width: '100%', - height: '150px', - penColor: 'black', - backgroundColor: 'rgb(245,245,235)', - minWidth: '0.5', - maxWidth: '2.5', - keepOverlayRatio: true, - id: 'ervvnoe', - }, - { - input: true, - tableView: true, - label: 'City, State, Zip', - key: 'cityStateZip', - type: 'textfield', - overlay: { width: 465, height: 21, left: 80.3438, top: 1084, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e4x5zp', - }, - { - hideLabel: true, - overlay: { - page: 1, - top: 1027.8, - left: 730.538, - height: 12.75628779296875, - width: 11.400024414062523, - style: '', - }, - type: 'checkbox', - value: 'marriedsingle', - name: 'status', - defaultValue: false, - key: 'marriedButSingle', - datagridLabel: true, - label: 'Married But Single', - tableView: true, - inputType: 'radio', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'eg81i4m', - }, - { - hideLabel: true, - overlay: { - page: 1, - top: 1027.4, - left: 652.938, - height: 13.618787792968659, - width: 13.400012207031228, - style: '', - }, - type: 'checkbox', - value: 'married', - name: 'status', - defaultValue: false, - key: 'married', - datagridLabel: true, - label: 'Married', - tableView: true, - inputType: 'radio', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'efb089c', - }, - { - hideLabel: true, - overlay: { - page: 1, - top: 1027, - left: 576.538, - height: 13.88128779296875, - width: 13.400012207031205, - style: '', - }, - type: 'checkbox', - value: 'single', - name: 'status', - defaultValue: false, - key: 'single', - datagridLabel: true, - label: 'Single', - tableView: true, - inputType: 'radio', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'emtvqvgq', - }, - { - overlay: { - page: 1, - top: 1044.2255555555555, - left: 81.30207777777777, - height: 21.10074501953125, - width: 466.72555555555556, - style: '', - }, - type: 'textfield', - key: 'homeAddress', - label: 'Home Address', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'ewtco6b', - }, - { - overlay: { - page: 1, - top: 998.6667777777777, - left: 789.0803333333333, - height: 23.47576724175342, - width: 234.0871314561631, - style: '', - }, - type: 'textfield', - key: 'ssn', - label: 'ssn', - inputMask: '999-99-9999', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'edz921k', - }, - { - overlay: { - page: 1, - top: 999.2222222222222, - left: 387.4138888888889, - height: 22.095556130642336, - width: 389.90500508626303, - style: '', - }, - type: 'textfield', - key: 'lastName', - label: 'Last Name', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e2de7sa', - }, - { - overlay: { - page: 1, - top: 998.6664444444444, - left: 81.85761111111108, - height: 23.24826724175342, - width: 299.9064457160102, - style: '', - }, - type: 'textfield', - key: 'firstName', - label: 'First Name', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'eq3xm7d', - }, - { - overlay: { - page: 1, - top: 750.3336666666667, - left: 972.9684444444445, - height: '18', - width: '50', - style: '', - }, - type: 'textfield', - key: 'h', - label: 'H', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'ej8thdm', - }, - { - input: true, - tableView: true, - label: 'G', - key: 'g', - type: 'textfield', - overlay: { width: '50', height: '18', left: 973.172, top: 726.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'esj0u5e', - }, - { - input: true, - tableView: true, - label: 'F', - key: 'f', - type: 'textfield', - overlay: { width: '50', height: '18', left: 973.172, top: 621.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e0kdkzp', - }, - { - input: true, - tableView: true, - label: 'E', - key: 'e', - type: 'textfield', - overlay: { width: '50', height: '18', left: 973.172, top: 599.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e4wp06', - }, - { - input: true, - tableView: true, - label: 'D', - key: 'd', - type: 'textfield', - overlay: { width: '50', height: '18', left: 972.672, top: 577.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'evg04s8', - }, - { - input: true, - tableView: true, - label: 'C', - key: 'c', - type: 'textfield', - overlay: { width: '50', height: '18', left: 972.672, top: 556.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e953emh', - }, - { - input: true, - tableView: true, - label: 'B', - key: 'b', - type: 'textfield', - overlay: { width: '50', height: '18', left: 972.672, top: 493, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e2l0zzm', - }, - { - input: true, - tableView: true, - label: 'A', - key: 'a', - type: 'textfield', - overlay: { width: '50', height: '18', left: 972.469, top: 449.375, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'egw3xvl', - }, - { - input: true, - label: 'Submit', - tableView: false, - key: 'submit', - type: 'button', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - size: 'md', - leftIcon: '', - rightIcon: '', - block: false, - action: 'submit', - disableOnInvalid: false, - theme: 'primary', - id: 'etn79o', - }, - ], - owner: '553dbfc08d22d5cb1a7024f2', - submissionAccess: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', - }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - tags: [], - type: 'form', - _vid: 0, - revisions: '', -}; -exports.example = { - _id: '57aa1d2a5b7a477b002717fe', - machineName: 'examples:example', - modified: '2022-12-09T17:14:46.932Z', - title: 'Example', - display: 'form', - type: 'form', - name: 'example', - path: 'example', - project: '5692b91fd1028f01000407e3', - created: '2016-08-09T18:12:58.126Z', - components: [ - { - input: false, - html: '

Form.io Example Form

\n\n

This is a dynamically rendered JSON form built with Form.io. Using a simple drag-and-drop form builder, you can create any form that includes e-signatures, wysiwyg editors, date fields, layout components, data grids, surveys, etc.

\n', - type: 'content', - conditional: { show: '', when: null, eq: '' }, - key: 'content', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - tableView: false, - modalEdit: false, - label: 'Content', - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - id: 'e4w5wnn', - addons: [], - }, - { - input: false, - columns: [ - { - components: [ - { - tabindex: '1', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - inputType: 'text', - inputMask: '', - label: 'First Name', - key: 'firstName', - placeholder: 'Enter your first name', - prefix: '', - suffix: '', - multiple: false, - defaultValue: '', - protected: false, - unique: false, - persistent: true, - validate: { - required: false, - minLength: '', - maxLength: '', - pattern: '', - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: '', when: null, eq: '' }, - type: 'textfield', - customClass: '', - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputFormat: 'plain', - spellcheck: true, - id: 'ek1pl3', - addons: [], - displayMask: '', - truncateMultipleSpaces: false, - }, - { - tabindex: '3', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - inputType: 'email', - label: 'Email', - key: 'email', - placeholder: 'Enter your email address', - prefix: '', - suffix: '', - defaultValue: '', - protected: false, - unique: false, - persistent: true, - type: 'email', - conditional: { show: '', when: null, eq: '' }, - kickbox: { enabled: false }, - customClass: '', - multiple: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputFormat: 'plain', - inputMask: '', - spellcheck: true, - id: 'en2328', - addons: [], - displayMask: '', - truncateMultipleSpaces: false, - }, - ], - width: 6, - offset: 0, - push: 0, - pull: 0, - size: 'md', - currentWidth: 6, - }, - { - components: [ - { - tabindex: '2', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - inputType: 'text', - inputMask: '', - label: 'Last Name', - key: 'lastName', - placeholder: 'Enter your last name', - prefix: '', - suffix: '', - multiple: false, - defaultValue: '', - protected: false, - unique: false, - persistent: true, - validate: { - required: false, - minLength: '', - maxLength: '', - pattern: '', - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: '', when: null, eq: '' }, - type: 'textfield', - customClass: '', - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputFormat: 'plain', - spellcheck: true, - id: 'ex6xzd', - addons: [], - displayMask: '', - truncateMultipleSpaces: false, - }, - { - tabindex: '4', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - inputMask: '(999) 999-9999', - label: 'Phone Number', - key: 'phoneNumber', - placeholder: 'Enter your phone number', - prefix: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - defaultValue: '', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - type: 'phoneNumber', - conditional: { show: '', when: null, eq: '' }, - customClass: '', - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: 'tel', - inputFormat: 'plain', - spellcheck: true, - inputMode: 'decimal', - id: 'ecee6s', - addons: [], - displayMask: '', - truncateMultipleSpaces: false, - }, - ], - width: 6, - offset: 0, - push: 0, - pull: 0, - size: 'md', - currentWidth: 6, - }, - ], - type: 'columns', - conditional: { show: '', when: null, eq: '' }, - key: 'columns', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: false, - refreshOn: '', - redrawOn: '', - tableView: false, - modalEdit: false, - label: 'Columns', - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - tree: false, - autoAdjust: false, - id: 'e2i9r0c', - addons: [], - lazyLoad: false, - }, - { - tabindex: '5', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - label: 'Survey', - key: 'survey', - questions: [ - { - value: 'howWouldYouRateTheFormIoPlatform', - label: 'How would you rate the Form.io platform?', - }, - { value: 'howWasCustomerSupport', label: 'How was Customer Support?' }, - { value: 'overallExperience', label: 'Overall Experience?' }, - ], - values: [ - { value: 'excellent', label: 'Excellent' }, - { value: 'great', label: 'Great' }, - { value: 'good', label: 'Good' }, - { value: 'average', label: 'Average' }, - { value: 'poor', label: 'Poor' }, - ], - defaultValue: '', - protected: false, - persistent: true, - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - type: 'survey', - conditional: { show: '', when: null, eq: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - unique: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - id: 'ek3vrnp', - addons: [], - }, - { - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - label: 'Signature', - key: 'signature', - placeholder: '', - footer: 'Sign above', - width: '100%', - height: '150px', - penColor: 'black', - backgroundColor: 'rgb(245,245,235)', - minWidth: '0.5', - maxWidth: '2.5', - protected: false, - persistent: true, - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - type: 'signature', - hideLabel: true, - conditional: { show: '', when: null, eq: '' }, - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - unique: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - id: 'e4zac8j', - addons: [], - keepOverlayRatio: true, - }, - { - tabindex: '6', - conditional: { eq: '', when: null, show: '' }, - tags: [], - input: true, - label: 'Submit', - tableView: false, - key: 'submit', - size: 'md', - leftIcon: '', - rightIcon: '', - block: false, - action: 'submit', - disableOnInvalid: true, - theme: 'primary', - type: 'button', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - id: 'et5j8rn', - addons: [], - }, - ], - owner: '554806425867f4ee203ea861', - submissionAccess: [ - { roles: ['5692b920d1028f01000407e6'], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - '000000000000000000000000', - ], - type: 'read_all', - }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - tags: [], - _vid: 0, - revisions: '', -}; -exports.simpleForm = { - _id: '641b2ba3488ffcafa27c2e9f', - title: 'Simple Form', - name: 'simpleForm', - path: 'simpleform', - type: 'form', - display: 'form', - tags: [], - components: [ - { - label: 'Required Field', - applyMaskOn: 'change', - tableView: true, - validate: { - required: true, - }, - key: 'requiredField', - type: 'textfield', - input: true, - }, - { - label: 'Maximum Words', - applyMaskOn: 'change', - autoExpand: false, - tableView: true, - validate: { - maxWords: 4, - }, - key: 'maximumWords', - type: 'textarea', - input: true, - }, - { - label: 'Minimum Words', - applyMaskOn: 'change', - autoExpand: false, - tableView: true, - validate: { - minWords: 2, - }, - key: 'minimumWords', - type: 'textarea', - input: true, - }, - { - label: 'Email', - applyMaskOn: 'change', - tableView: true, - key: 'email', - type: 'email', - input: true, - }, - { - label: 'Url', - applyMaskOn: 'change', - tableView: true, - key: 'url', - type: 'url', - input: true, - }, - { - label: 'Input Mask', - applyMaskOn: 'change', - tableView: true, - key: 'inputMask', - type: 'phoneNumber', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { - type: 'input', - }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { - show: null, - when: null, - eq: '', - }, - overlay: { - style: '', - left: '', - top: '', - width: '', - height: '', - }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'tel', - inputFormat: 'plain', - inputMask: '(999) 999-9999', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - inputMode: 'decimal', - id: 'e8vls3a', - keyModified: true, - }, - { - type: 'button', - label: 'Submit', - key: 'submit', - disableOnInvalid: true, - input: true, - tableView: false, - }, - ], - settings: {}, - properties: {}, - project: '6419d8f2322509215938a9e6', - controller: '', - revisions: '', - submissionRevisions: '', - _vid: 0, - created: '2023-03-22T16:24:03.220Z', - modified: '2023-03-22T16:27:12.193Z', - machineName: 'qgvzeueerscrxbs:simpleForm', -}; -exports.wizard = { - _id: '578f930ef1912f8000459a50', - machineName: 'examples:wizard', - modified: '2022-11-17T20:30:28.519Z', - title: 'Wizard', - display: 'wizard', - type: 'form', - name: 'wizard', - path: 'wizard', - project: '5692b91fd1028f01000407e3', - created: '2016-07-20T15:04:46.906Z', - components: [ - { - key: 'page1', - input: false, - components: [ - { - type: 'textfield', - multiple: true, - key: 'textfieldonpage1', - label: 'Textfield on page 1', - tableView: true, - input: true, - }, - { - type: 'number', - validate: { required: true }, - defaultValue: 0, - key: 'numberField', - label: 'Number Field', - inputType: 'number', - tableView: true, - input: true, - }, - ], - title: 'First', - type: 'panel', - tableView: false, - label: 'Panel', - }, - { - tableView: false, - key: 'page2', - input: false, - components: [ - { - type: 'textfield', - validate: { required: true }, - key: 'textfieldonPage2', - label: 'Textfield on Page 2', - tableView: true, - input: true, - }, - { - input: true, - tableView: true, - label: 'Customer', - key: 'page2Customer', - placeholder: 'Select a customer', - data: { - url: 'https://examples.form.io/customer/submission', - headers: [{ value: '', key: '' }], - }, - dataSrc: 'url', - valueProperty: 'data.email', - template: '{{ item.data.firstName }} {{ item.data.lastName }}', - type: 'select', - widget: 'html5', - searchField: 'data.email', - }, - { - clearOnHide: false, - type: 'fieldset', - components: [ - { - type: 'textfield', - key: 'textfield', - label: 'Textfield', - tableView: true, - input: true, - }, - ], - legend: 'FieldSet Label', - tableView: true, - input: false, - key: 'fieldSet', - label: 'Field Set', - }, - ], - title: 'Page 2', - type: 'panel', - label: 'Panel', - }, - { - type: 'panel', - components: [ - { - input: true, - tableView: true, - label: 'Text', - key: 'panelText', - validate: { required: true }, - type: 'textfield', - }, - { - type: 'datagrid', - key: 'panelDataGrid', - label: 'Data Grid', - tableView: true, - components: [ - { - hideLabel: true, - type: 'textfield', - key: 'panelDataGridA', - label: 'A', - tableView: true, - input: true, - inDataGrid: true, - }, - { - hideLabel: true, - type: 'textfield', - key: 'panelDataGridB', - label: 'B', - tableView: true, - input: true, - inDataGrid: true, - }, - { - hideLabel: true, - type: 'textfield', - key: 'panelDataGridC', - label: 'C', - tableView: true, - input: true, - inDataGrid: true, - }, - { - hideLabel: true, - type: 'textfield', - key: 'panelDataGridD', - label: 'D', - tableView: true, - input: true, - inDataGrid: true, - }, - ], - input: true, - }, - { - input: true, - tableView: true, - label: 'HTML5 Select', - key: 'panelHtml5Select', - data: { - values: [ - { value: 'orange', label: 'Orange' }, - { value: 'apple', label: 'Apple' }, - { value: 'banana', label: 'Banana' }, - { value: 'strawberry', label: 'Strawberry' }, - { value: 'kiwi', label: 'Kiwi' }, - ], - }, - widget: 'html5', - type: 'select', - }, - ], - tableView: false, - title: 'Page 3', - input: false, - key: 'panel', - label: 'Panel', - }, - { - key: 'page3', - input: false, - components: [ - { - type: 'textfield', - key: 'textfieldonPage3', - label: 'Textfield on Page 3', - tableView: true, - input: true, - }, - { - input: true, - tableView: true, - label: 'I agree to the follow the rules', - dataGridLabel: false, - key: 'page3Iagreetothefollowtherules', - defaultValue: false, - type: 'checkbox', - }, - { - input: true, - tableView: true, - label: 'Signature', - key: 'signature', - type: 'signature', - hideLabel: true, - lockKey: true, - }, - ], - title: 'Last', - type: 'panel', - tableView: false, - label: 'Panel', - }, - { - type: 'button', - disableOnInvalid: true, - key: 'submit', - tableView: false, - label: 'Submit', - input: true, - }, - ], - owner: '55673dc04f0405dd28205bb7', - submissionAccess: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: ['5692b920d1028f01000407e6'], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', - }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - tags: ['common'], - settings: { - controller: - "['$scope', function($scope) { $scope.$watch('submission.data', function(data) { console.log(data); }, true); }]", - }, - revisions: '', - _vid: 0, - controller: '', - properties: {}, -}; -exports.inlineEmbedFormPortal = { - _id: '617c032c68daf082ce063303', - type: 'form', - tags: [], - owner: '5e4aa9cf4037892ed27d5550', - components: [ - { - label: 'HTML', - tag: 'div', - attrs: [{ attr: '', value: '' }], - content: - "

Quick Inline Embed

\r\n

To quickly embed this form without using any framework, you can use the following code snippit and configure it using the Inline Embed Configuration form below.

\r\n

See our Inline Embed Documentation to know more about it.

", - refreshOnChange: false, - key: 'html1', - type: 'htmlelement', - input: false, - tableView: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'emraund', - }, - { - label: 'HTML', - tag: 'pre', - attrs: [{ attr: '', value: '' }], - content: - '', - refreshOnChange: true, - key: 'html', - type: 'htmlelement', - input: false, - tableView: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'e3wopjp', - }, - { - label: 'Copy to Clipboard', - action: 'custom', - showValidations: false, - theme: 'success', - block: true, - leftIcon: 'fa fa-copy', - tableView: false, - key: 'copyToClipboard', - type: 'button', - custom: 'var embedCode = document.getElementById(\'embed-code\');\nif (embedCode) {\n embedCode.focus();\n embedCode.select();\n document.execCommand("copy");\n}', - input: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - size: 'md', - rightIcon: '', - disableOnInvalid: false, - id: 'eq2y2ul', - }, - { - title: 'Inline Embed Configuration', - collapsible: false, - key: 'embedConfiguration', - type: 'panel', - label: 'Inline Embed Configuration', - input: false, - tableView: false, - components: [ - { - label: 'Embed Script', - customDefaultValue: "value = instance.options?.quickInlineEmbed || '';", - key: 'embed', - type: 'hidden', - tableView: true, - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'eq04647', - }, - { - label: 'Project', - tableView: true, - key: 'project', - type: 'hidden', - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'eowdp4', - }, - { - label: 'Base', - tableView: true, - key: 'base', - type: 'hidden', - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'e2ayb69', - }, - { - label: 'Form Url', - customDefaultValue: "value = instance.options?.embedFormSrc || '';", - key: 'src', - type: 'hidden', - input: true, - tableView: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - inputType: 'hidden', - id: 'ep1qgx', - }, - { - label: 'Template', - widget: 'choicesjs', - tableView: true, - data: { - values: [ - { label: 'Boostrap 4', value: 'false' }, - { label: 'USWDS', value: 'uswds' }, - ], - json: '', - url: '', - resource: '', - custom: '', - }, - key: 'template', - type: 'select', - input: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - onlyAvailableItems: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - idPath: 'id', - clearOnRefresh: false, - limit: 100, - dataSrc: 'values', - valueProperty: '', - lazyLoad: true, - filter: '', - searchEnabled: true, - searchDebounce: 0.3, - searchField: '', - minSearch: 0, - readOnlyValue: false, - authenticate: false, - ignoreCache: false, - template: '{{ item.label }}', - selectFields: '', - selectThreshold: 0.3, - uniqueOptions: false, - fuseOptions: { include: 'score', threshold: 0.3 }, - indexeddb: { filter: {} }, - customOptions: {}, - useExactSearch: false, - id: 'ewk9iop', - }, - { - title: 'Advanced Settings', - collapsible: true, - key: 'advancedSettings', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Redirect', - tooltip: - 'The URL you would like to redirect to after the form is submitted. ', - tableView: true, - key: 'redirect', - type: 'url', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'url', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'et7ayx', - }, - { - label: 'Submission Endpoint', - tooltip: - 'The endpoint you would like to POST the submission toward. This allows you to send the submission to endpoints other than the default submission endpoint.', - tableView: true, - key: 'submit', - type: 'url', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'url', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'epa9s3i', - }, - { - label: 'Inherit Page CSS', - tooltip: - 'When it is unchecked, it loads all dependent CSS libraries to render the form.', - tableView: false, - defaultValue: false, - calculateValue: 'if (data.encapsulate) {\n value = true;\n}', - key: 'inherit', - type: 'checkbox', - input: true, - calculateValueMode: 'json', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - inputType: 'checkbox', - value: '', - name: '', - id: 'e23lxjq', - }, - { - label: 'Debug Mode', - tooltip: - 'Add a number of console.log records to the browser on how this form is progressing through the embedding code.', - tableView: false, - defaultValue: false, - key: 'debug', - type: 'checkbox', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - inputType: 'checkbox', - value: '', - name: '', - id: 'eh4hyc', - }, - { - label: 'Custom Configurations', - description: - 'The following FormioConfig parameters can be specified: config, form, submission, libs.\n

Example:\n { "config": { "readOnly": true } }.\n
Click here for more examples.\n

\n', - tooltip: - 'Add configuration in JSON format for the global FormioConfig variable to control the embedded flow', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'config', - type: 'textarea', - as: 'json', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - minWords: '', - maxWords: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'html', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - rows: 3, - wysiwyg: false, - fixedSize: true, - id: 'elmjv3ki', - }, - { - label: 'Before Render Handler', - description: - 'The callback accepts the following parameters: Formio, element, config. \n

Example:\nfunction(Formio, element, config) { console.log(Formio, element, config); }\n

', - tooltip: - 'Provide a callback that is executed before the Form is rendered.', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'before', - type: 'textarea', - as: 'string', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - minWords: '', - maxWords: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'html', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - rows: 3, - wysiwyg: false, - fixedSize: true, - id: 'ekd4ovh', - }, - { - label: 'After Render Handler', - description: - 'The callback accepts instance variable as a parameter.\n

Example: function(instance) { console.log(instance); }\n

', - tooltip: - 'Provide a callback that is called after the form is done rendering.', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'after', - type: 'textarea', - as: 'string', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - minWords: '', - maxWords: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'html', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - rows: 3, - wysiwyg: false, - fixedSize: true, - id: 'eiqb29', - }, - ], - collapsed: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - tree: false, - lazyLoad: false, - theme: 'default', - breadcrumb: 'default', - id: 'e71fwgr', - }, - ], - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - tree: false, - lazyLoad: false, - theme: 'default', - breadcrumb: 'default', - id: 'e8be5t4', - }, - ], - revisions: 'current', - _vid: 4, - title: 'Inline Embed Form - Portal', - display: 'form', - access: [ - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', - }, - ], - submissionAccess: [], - controller: '', - properties: {}, - settings: {}, - name: 'inlineEmbedFormPortal', - path: 'inlineembedformportal', - project: '5692b91fd1028f01000407e3', - created: '2021-10-29T14:20:28.581Z', - modified: '2022-11-17T15:09:31.641Z', - machineName: 'examples:inlineEmbedFormPortal', -}; -exports.validationRulesNyHealth = { - _id: '617051c6a8135f6a0780c364', - type: 'form', - tags: [], - owner: '5d921ec842af9789e5b81b26', - components: [ - { - title: 'Case 1', - collapsible: false, - key: 'case1', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 1:

\n

Box a value can not differ by a factor(.5) of n from Box b

\n• EX: 100(b) -> a(max)50', - refreshOnChange: false, - key: 'html1', - type: 'htmlelement', - input: false, - tableView: false, - }, - { - label: 'Box a', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - validate: { - customMessage: 'Needs to be within the range. ', - custom: 'valid = input >= (data.boxB * 0.5) && input <= (data.boxB * 1.5);', - }, - errorLabel: 'Box A Value', - key: 'boxA', - type: 'number', - input: true, - }, - { - label: 'Box b', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - key: 'boxB', - type: 'number', - input: true, - }, - ], - }, - { - title: 'Case 2 / Case 3', - collapsible: false, - key: 'case2', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 2:

\n

Box b must compare the value on the number of repeating section

\n• Value of b must match the amount of repeating section
\n• Number of repeating sections must not exceed value of b\n\n

Case 3:

\n

Box b in a repeating section 1a must be unique in all repeating section

', - refreshOnChange: false, - key: 'html', - type: 'htmlelement', - input: false, - tableView: false, - }, - { - label: 'Box b', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - calculateValue: - "var dataGrid = instance.root.getComponent('dataGrid');\ndataGrid.component.validate.minLength = parseInt(value, 10);\ndataGrid.component.validate.maxLength = parseInt(value, 10);\ninstance.root.redraw();", - key: 'boxB1', - type: 'number', - input: true, - }, - { - label: 'Data Grid', - reorder: false, - addAnotherPosition: 'bottom', - layoutFixed: false, - enableRowGroups: false, - initEmpty: false, - tableView: false, - defaultValue: [{ uniqueName: '' }], - key: 'dataGrid', - type: 'datagrid', - input: true, - components: [ - { - label: 'Unique Name', - tableView: true, - unique: true, - key: 'uniqueName', - type: 'textfield', - input: true, - }, - ], - }, - ], - breadcrumbClickable: true, - buttonSettings: { previous: true, cancel: true, next: true }, - scrollToTop: false, - }, - { - title: 'Case 4', - collapsible: false, - key: 'case7', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 4:

\n

Box b in a repeating section a1 must be greater then Box b in repeating section a2.

', - refreshOnChange: false, - key: 'html2', - type: 'htmlelement', - input: false, - tableView: false, - }, - { - title: 'Case 4.1', - collapsible: false, - key: 'case4', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Number1', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - key: 'number1', - type: 'number', - input: true, - }, - ], - }, - { - title: 'Case 4.2', - collapsible: false, - key: 'case42', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Number2', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - validate: { - customMessage: 'Value must be greater than or equal to Number1', - custom: 'valid = input>=data.number1;', - }, - key: 'number2', - type: 'number', - input: true, - }, - ], - }, - ], - }, - { - title: 'Case 5', - collapsible: false, - key: 'case5', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 5:

\n

Box b in a repeating section a1 must be greater than Box c in repeating section a1. and also it can be applied to fields outside repeating section

\n', - refreshOnChange: false, - key: 'html3', - type: 'htmlelement', - input: false, - tableView: false, - }, - { - label: 'Data Grid', - reorder: false, - addAnotherPosition: 'bottom', - layoutFixed: false, - enableRowGroups: false, - initEmpty: false, - tableView: false, - defaultValue: [{}], - key: 'dataGrid1', - type: 'datagrid', - input: true, - components: [ - { - label: 'Number3', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - key: 'number3', - type: 'number', - input: true, - }, - { - label: 'Number4', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - validate: { - customMessage: 'must be greater than the value in Number3', - custom: 'valid = input>row.number3;\n', - }, - errorLabel: 'Number4', - key: 'number4', - type: 'number', - input: true, - }, - ], - }, - { - title: 'Case 5 - Number outside of Section', - tooltip: - 'This is dependent on which value in the repeating section above would need to be validated against.', - collapsible: false, - key: 'case5NumberOutsideOfSection1', - type: 'panel', - label: 'Case 5 - Number outside of Section', - input: false, - tableView: false, - components: [ - { - label: 'Number5', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - validate: { - customMessage: 'Value must be greater than Number3', - custom: 'valid = input>data.number3;', - }, - key: 'number6', - type: 'number', - input: true, - }, - ], - }, - ], - }, - { - title: 'Case 6 - Min / Max Date from Today', - collapsible: false, - key: 'case6', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 6:

\n

Date field d should have a date that is at most/least N days/weeks/months/years ago/ from today\n \n

', - refreshOnChange: false, - key: 'html4', - type: 'htmlelement', - input: false, - tableView: false, - }, - { - label: 'Date / Time', - tableView: false, - enableMinDateInput: true, - datePicker: { - disableWeekends: false, - disableWeekdays: false, - maxDate: "moment().add(10, 'days')", - minDate: "moment().subtract(10, 'days')", - }, - enableMaxDateInput: true, - key: 'dateTime', - type: 'datetime', - input: true, - widget: { - type: 'calendar', - displayInTimezone: 'viewer', - locale: 'en', - useLocaleSettings: false, - allowInput: true, - mode: 'single', - enableTime: true, - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - hourIncrement: 1, - minuteIncrement: 1, - time_24hr: false, - minDate: "moment().subtract(10, 'days')", - disableWeekends: false, - disableWeekdays: false, - maxDate: "moment().add(10, 'days')", - }, - }, - ], - }, - { - type: 'button', - label: 'Submit', - key: 'submit', - disableOnInvalid: true, - input: true, - tableView: false, - }, - ], - revisions: '', - _vid: 0, - title: 'Validation Rules - NY Health', - display: 'wizard', - access: [ - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', - }, - ], - submissionAccess: [], - controller: '', - properties: {}, - settings: {}, - name: 'validationRulesNyHealth', - path: 'validationrulesnyhealth', - project: '5692b91fd1028f01000407e3', - created: '2021-10-20T17:28:38.165Z', - modified: '2021-10-20T18:08:13.287Z', - machineName: 'examples:validationRulesNyHealth', -}; -exports.inlineembed = { - _id: '60089c6795f584688609f83c', - type: 'form', - tags: [], - owner: '553dbfc08d22d5cb1a7024f2', - components: [ - { - html: '

This is a form that enables the configuration of a Quick Inline Embed for a Form.io form.

For advanced documentation on how to use this embedding feature, please see our Quick Inline Embed Documentation.

', - label: 'Content', - refreshOnChange: false, - key: 'content', - type: 'content', - input: false, - tableView: false, - }, - { - label: 'Columns', - columns: [ - { - components: [ - { - title: 'Embed Configuration', - collapsible: false, - key: 'embedConfiguration', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Embed Script', - defaultValue: 'https://cdn.form.io/formiojs/formio.embed.js', - key: 'embed', - type: 'hidden', - tableView: true, - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - }, - { - label: 'Project', - tableView: true, - key: 'project', - type: 'hidden', - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - }, - { - label: 'Base', - tableView: true, - key: 'base', - type: 'hidden', - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - }, - { - label: 'Form URL', - tableView: true, - validate: { required: true }, - key: 'src', - type: 'textfield', - input: true, - defaultValue: 'https://examples.form.io/example', - hideOnChildrenHidden: false, - }, - { - label: 'Template', - widget: 'choicesjs', - tableView: true, - data: { - values: [ - { label: 'Boostrap 4', value: 'false' }, - { label: 'USWDS', value: 'uswds' }, - ], - }, - key: 'template', - type: 'select', - input: true, - searchThreshold: 0.3, - hideOnChildrenHidden: false, - }, - { - title: 'Advanced Settings', - collapsible: true, - key: 'advancedSettings', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Redirect', - tableView: true, - key: 'redirect', - type: 'url', - input: true, - }, - { - label: 'Submission Endpoint', - tableView: true, - key: 'submit', - type: 'url', - input: true, - }, - { - label: 'Inherit Page CSS', - tableView: false, - defaultValue: true, - calculateValue: - 'if (data.encapsulate) {\n value = true;\n}', - key: 'inherit', - type: 'checkbox', - input: true, - }, - { - label: 'Debug Mode', - tableView: false, - key: 'debug', - type: 'checkbox', - input: true, - defaultValue: false, - }, - { - label: 'Custom Configurations', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'config', - type: 'textarea', - as: 'json', - input: true, - }, - { - input: true, - key: 'before', - tableView: true, - label: 'Before Render Handler', - type: 'textarea', - editor: 'ace', - as: 'string', - }, - { - label: 'After Render Handler', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'after', - type: 'textarea', - as: 'string', - input: true, - }, - ], - collapsed: true, - hideOnChildrenHidden: false, - }, - ], - hideOnChildrenHidden: false, - }, - ], - width: 6, - offset: 0, - push: 0, - pull: 0, - size: 'md', - currentWidth: 6, - }, - { - components: [ - { - title: 'Embed Code', - collapsible: false, - key: 'embedCode', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'HTML', - tag: 'pre', - attrs: [{ attr: '', value: '' }], - content: - '', - refreshOnChange: true, - key: 'html', - type: 'htmlelement', - input: false, - tableView: false, - }, - { - label: 'Copy to Clipboard', - action: 'custom', - showValidations: false, - theme: 'success', - block: true, - leftIcon: 'fa fa-copy', - tableView: false, - key: 'copyToClipboard', - type: 'button', - custom: 'var embedCode = document.getElementById(\'embed-code\');\nif (embedCode) {\n embedCode.focus();\n embedCode.select();\n document.execCommand("copy");\n}', - input: true, - hideOnChildrenHidden: false, - }, - ], - hideOnChildrenHidden: false, - }, - ], - width: 6, - offset: 0, - push: 0, - pull: 0, - size: 'md', - currentWidth: 6, - }, - ], - hideOnChildrenHidden: false, - key: 'columns', - type: 'columns', - input: false, - tableView: false, - }, - ], - revisions: '', - _vid: 0, - title: 'Quick Inline Embed', - display: 'form', - access: [ - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', - }, - ], - submissionAccess: [], - controller: '', - properties: {}, - settings: {}, - name: 'inlineembed', - path: 'embed', - project: '5692b91fd1028f01000407e3', - created: '2021-01-20T21:11:03.957Z', - modified: '2021-10-18T16:34:28.512Z', - machineName: 'examples:inlineEmbedConfiguration', -}; -exports.customerLoad = { - _id: '5aa316c59f3918304b469e82', - title: 'Customer Load', - display: 'form', - type: 'form', - components: [ - { - input: true, - tableView: true, - inputType: 'number', - label: 'Customer Number', - key: 'customerNumber', - validate: { required: true, min: 1, max: 9 }, - type: 'number', - }, - { input: true, tableView: true, label: 'Name', key: 'name', type: 'textfield' }, - { - input: true, - tableView: true, - label: 'Phone Number', - key: 'phoneNumber', - type: 'textfield', - }, - { input: true, label: 'Submit', tableView: false, key: 'submit', type: 'button' }, - ], - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - '000000000000000000000000', - ], - type: 'read_all', - }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - submissionAccess: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - settings: {}, - name: 'customerLoad', - path: 'customerload', - owner: '55673dc04f0405dd28205bb7', - project: '5692b91fd1028f01000407e3', - tags: [], - created: '2018-03-09T23:20:37.966Z', - revisions: '', - _vid: 0, - modified: '2021-09-15T17:09:44.770Z', - machineName: 'examples:customerLoad', -}; -exports.kitchenSink = { - _id: '5d7a42f21cc1c2ca88ff2dd5', - type: 'form', - tags: [], - owner: '553dbfc08d22d5cb1a7024f2', - components: [ - { - label: 'Panel', - title: 'User Information', - collapsible: false, - mask: false, - tableView: false, - alwaysEnabled: false, - type: 'panel', - input: false, - key: 'panel2', - components: [ - { - label: 'Columns', - columns: [ - { - components: [ - { - label: 'First Name', - placeholder: 'Enter your first Name', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'firstName', - validate: { required: true }, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - hideOnChildrenHidden: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - width: 5, - offset: 0, - push: 0, - pull: 0, - type: 'column', - input: false, - hideOnChildrenHidden: false, - key: 'column', - tableView: true, - label: 'Column', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - dataGridLabel: false, - labelPosition: 'top', - labelWidth: 30, - labelMargin: 3, - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - allowCalculateOverride: false, - widget: null, - refreshOn: '', - clearOnRefresh: false, - validateOn: 'change', - validate: { required: false, custom: '', customPrivate: false }, - conditional: { show: null, when: null, eq: '' }, - id: 'eu6xaap', - size: 'md', - currentWidth: 5, - }, - { - components: [ - { - label: 'Middle Name', - placeholder: 'Enter your middle name', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'middleName', - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - hideOnChildrenHidden: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - width: 2, - offset: 0, - push: 0, - pull: 0, - type: 'column', - input: false, - hideOnChildrenHidden: false, - key: 'column', - tableView: true, - label: 'Column', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - dataGridLabel: false, - labelPosition: 'top', - labelWidth: 30, - labelMargin: 3, - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - allowCalculateOverride: false, - widget: null, - refreshOn: '', - clearOnRefresh: false, - validateOn: 'change', - validate: { required: false, custom: '', customPrivate: false }, - conditional: { show: null, when: null, eq: '' }, - id: 'eorxgl', - size: 'md', - currentWidth: 2, - }, - { - width: 5, - offset: 0, - push: 0, - pull: 0, - type: 'column', - input: false, - hideOnChildrenHidden: false, - key: 'column', - tableView: true, - label: 'Column', - components: [ - { - label: 'Last Name', - placeholder: 'Enter your last name', - description: - 'This is the name that should be on your birth certificate.', - tooltip: 'Seriously? You still need help with this one?', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'lastName', - validate: { required: true }, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - hideOnChildrenHidden: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - dataGridLabel: false, - labelPosition: 'top', - labelWidth: 30, - labelMargin: 3, - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - allowCalculateOverride: false, - widget: null, - refreshOn: '', - clearOnRefresh: false, - validateOn: 'change', - validate: { required: false, custom: '', customPrivate: false }, - conditional: { show: null, when: null, eq: '' }, - id: 'e02wdt8', - size: 'md', - currentWidth: 5, - }, - ], - mask: false, - tableView: false, - alwaysEnabled: false, - type: 'columns', - input: false, - key: 'columns', - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - hideOnChildrenHidden: false, - }, - { - input: true, - tableView: true, - label: 'Email', - key: 'panel2Email', - type: 'email', - labelWidth: 30, - labelMargin: 3, - widget: { - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - label: 'Website', - inputMasks: [{ label: '', mask: '' }], - alwaysEnabled: false, - tableView: true, - key: 'website', - type: 'url', - input: true, - }, - { - key: 'panel2Panel', - input: false, - title: 'Other Information', - theme: 'primary', - tableView: false, - components: [ - { - input: true, - tableView: true, - label: 'Phone Number', - key: 'panel2PhoneNumber', - type: 'phoneNumber', - labelWidth: 30, - labelMargin: 3, - widget: { - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: false, - inputType: 'password', - label: 'Password', - key: 'panel2Password', - protected: true, - type: 'password', - labelWidth: 30, - labelMargin: 3, - widget: { - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - label: 'SSN', - inputMask: '999 - 99 - 9999', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'ssn', - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - input: true, - tableView: true, - label: 'Birthday', - key: 'panel2Birthday', - datePicker: { datepickerMode: 'day' }, - type: 'datetime', - suffix: '\n', - widget: { - type: 'calendar', - displayInTimezone: 'viewer', - locale: 'en', - useLocaleSettings: false, - allowInput: true, - mode: 'single', - enableTime: true, - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - hourIncrement: 1, - minuteIncrement: 1, - time_24hr: false, - minDate: null, - maxDate: null, - }, - defaultValue: null, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - inputType: 'text', - label: 'Salary', - key: 'salary', - suffix: 'USD', - delimiter: true, - decimalLimit: 2, - requireDecimal: true, - type: 'currency', - tooltip: 'Enter your yearly salary', - description: 'Your yearly earnings before taxes.', - lockKey: true, - labelWidth: 30, - labelMargin: 3, - widget: null, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - inputType: 'number', - label: 'Number of Pets', - key: 'panel2NumberofPets', - prefix: '#', - type: 'number', - labelWidth: 30, - labelMargin: 3, - widget: null, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Favorite Month', - key: 'panel2FavoriteMonth', - data: { - values: [ - { value: 'january', label: 'January' }, - { value: 'february', label: 'February' }, - { value: 'march', label: 'March' }, - { value: 'april', label: 'April' }, - { value: 'may', label: 'May' }, - { value: 'june', label: 'June' }, - { value: 'july', label: 'July' }, - { value: 'august', label: 'August' }, - { value: 'september', label: 'September' }, - { value: 'october', label: 'October' }, - { value: 'november', label: 'November' }, - { value: 'december', label: 'December' }, - ], - }, - valueProperty: 'value', - defaultValue: 'may', - type: 'select', - labelWidth: 30, - labelMargin: 3, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Favorite Things', - key: 'panel2FavoriteThings', - data: { - values: [ - { value: 'raindropsOnRoses', label: 'Raindrops on roses' }, - { value: 'whiskersOnKittens', label: 'Whiskers on Kittens' }, - { - value: 'brightCopperKettles', - label: 'Bright Copper Kettles', - }, - { value: 'warmWoolenMittens', label: 'Warm Woolen Mittens' }, - ], - }, - valueProperty: 'value', - multiple: true, - type: 'select', - labelWidth: 30, - labelMargin: 3, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Message', - key: 'panel2PanelMessage', - type: 'textarea', - inputFormat: 'plain', - }, - { - input: true, - tableView: true, - label: 'Favorite Color', - key: 'panel2FavoriteColor', - values: [ - { value: 'blue', label: 'Blue', shortcut: '' }, - { value: 'red', label: 'Red', shortcut: '' }, - { value: 'green', label: 'Green', shortcut: '' }, - { value: 'yellow', label: 'Yellow', shortcut: '' }, - { value: 'purple', label: 'Purple', shortcut: '' }, - { value: 'orange', label: 'Orange', shortcut: '' }, - ], - type: 'radio', - optionsLabelPosition: 'right', - tooltip: 'Select your favorite color.', - inline: true, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Favorite Fruits', - key: 'panel2FavoriteFruits', - values: [ - { value: 'apple', label: 'Apple', shortcut: '' }, - { value: 'orange', label: 'Orange', shortcut: '' }, - { value: 'banana', label: 'Banana', shortcut: '' }, - { value: 'peach', label: 'Peach', shortcut: '' }, - { value: 'strawberry', label: 'Strawberry', shortcut: '' }, - ], - type: 'selectboxes', - optionsLabelPosition: 'right', - inputType: 'checkbox', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - ], - type: 'panel', - collapsible: true, - collapsed: true, - label: 'Panel', - }, - { - label: 'Bio', - editor: 'ckeditor', - tableView: true, - alwaysEnabled: false, - wysiwyg: { - theme: 'snow', - placeholder: '', - modules: { - clipboard: { matchVisual: false }, - toolbar: [ - [{ size: ['small', false, 'large', 'huge'] }], - [{ header: [1, 2, 3, 4, 5, 6, false] }], - [{ font: [] }], - [ - 'bold', - 'italic', - 'underline', - 'strike', - { script: 'sub' }, - { script: 'super' }, - 'clean', - ], - [{ color: [] }, { background: [] }], - [ - { list: 'ordered' }, - { list: 'bullet' }, - { indent: '-1' }, - { indent: '+1' }, - { align: [] }, - ], - ['blockquote', 'code-block'], - ['link', 'image', 'video', 'formula', 'source'], - ], - }, - rows: 10, - base64Upload: true, - image: { - toolbar: [ - 'imageTextAlternative', - '|', - 'imageStyle:alignLeft', - 'imageStyle:alignCenter', - 'imageStyle:full', - 'imageStyle:alignRight', - ], - styles: ['full', 'side', 'alignLeft', 'alignCenter', 'alignRight'], - }, - disableNativeSpellChecker: false, - mediaEmbed: { previewsInData: true }, - }, - rows: 10, - type: 'textarea', - input: true, - key: 'bio', - defaultValue: '


', - inputFormat: 'plain', - autoExpand: false, - isUploadEnabled: false, - reorder: false, - widget: { - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - collapsed: false, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - path: 'panel2', - }, - { - label: 'Education', - reorder: false, - mask: false, - tableView: true, - alwaysEnabled: false, - type: 'editgrid', - input: true, - key: 'education', - components: [ - { - label: 'School', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'school', - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Degree', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'degree', - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Graduation Date', - hideInputLabels: false, - inputsLabelPosition: 'top', - fields: { day: { hide: false }, month: { hide: false }, year: { hide: false } }, - useLocaleSettings: false, - mask: false, - tableView: true, - alwaysEnabled: false, - type: 'day', - input: true, - key: 'graduationDate', - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - templates: { - header: '
\n {%util.eachComponent(components, function(component) { %} \n
\n {{ component.label }} \n
\n {% }) %} \n
', - row: '
\n {% util.eachComponent(components, function(component) { %}\n
\n {{ getView(component, row[component.key]) }}\n
\n {% }) %}\n {% if (!instance.options.readOnly) { %}\n
\n
\n \n \n
\n
\n {% } %}\n
', - }, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - removeRow: '', - }, - { - label: 'Survey', - alwaysEnabled: false, - tableView: false, - questions: [ - { label: 'Food', value: 'food' }, - { label: 'Experience', value: 'experience' }, - { label: 'Restrooms', value: 'restrooms' }, - { label: 'Staff', value: 'staff' }, - ], - values: [ - { label: 'Very Good', value: 'veryGood' }, - { label: 'Good', value: 'good' }, - { label: 'Average', value: 'average' }, - { label: 'Bad', value: 'bad' }, - { label: 'Awful', value: 'awful' }, - ], - key: 'survey1', - type: 'survey', - input: true, - }, - { - label: 'Children', - alwaysEnabled: false, - tableView: false, - key: 'children', - type: 'well', - input: false, - components: [ - { - label: 'Children', - reorder: false, - addAnotherPosition: 'bottom', - defaultOpen: false, - layoutFixed: false, - enableRowGroups: false, - alwaysEnabled: false, - tableView: false, - key: 'children', - type: 'datagrid', - input: true, - components: [ - { - label: 'First Name', - widget: { - i18n: { - lng: 'en', - resources: { - en: { - translation: { - complete: 'Submission Complete', - error: 'Please fix the following errors before submitting.', - required: '{{field}} is required', - pattern: - '{{field}} does not match the pattern {{pattern}}', - minLength: - '{{field}} must be longer than {{length}} characters.', - maxLength: - '{{field}} must be shorter than {{length}} characters.', - minWords: - '{{field}} must have more than {{length}} words.', - maxWords: - '{{field}} must have less than {{length}} words.', - min: '{{field}} cannot be less than {{min}}.', - max: '{{field}} cannot be greater than {{max}}.', - minSelectedCount: - 'You must select at least {{minCount}} items to continue.', - maxSelectedCount: - 'You can only select up to {{maxCount}} items to continue.', - maxDate: - '{{field}} should not contain date after {{- maxDate}}', - minDate: - '{{field}} should not contain date before {{- minDate}}', - invalid_email: '{{field}} must be a valid email.', - invalid_url: '{{field}} must be a valid url.', - invalid_regex: - '{{field}} does not match the pattern {{regex}}.', - invalid_date: '{{field}} is not a valid date.', - invalid_day: '{{field}} is not a valid day.', - mask: '{{field}} does not match the mask.', - stripe: '{{stripe}}', - month: 'Month', - day: 'Day', - year: 'Year', - january: 'January', - february: 'February', - march: 'March', - april: 'April', - may: 'May', - june: 'June', - july: 'July', - august: 'August', - september: 'September', - october: 'October', - november: 'November', - december: 'December', - next: 'Next', - previous: 'Previous', - cancel: 'Cancel', - submit: 'Submit Form', - }, - }, - }, - }, - language: 'en', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - alwaysEnabled: false, - tableView: true, - key: 'firstName', - type: 'textfield', - input: true, - inDataGrid: true, - row: '0-0', - }, - { - label: 'Last Name', - widget: { - i18n: { - lng: 'en', - resources: { - en: { - translation: { - complete: 'Submission Complete', - error: 'Please fix the following errors before submitting.', - required: '{{field}} is required', - pattern: - '{{field}} does not match the pattern {{pattern}}', - minLength: - '{{field}} must be longer than {{length}} characters.', - maxLength: - '{{field}} must be shorter than {{length}} characters.', - minWords: - '{{field}} must have more than {{length}} words.', - maxWords: - '{{field}} must have less than {{length}} words.', - min: '{{field}} cannot be less than {{min}}.', - max: '{{field}} cannot be greater than {{max}}.', - minSelectedCount: - 'You must select at least {{minCount}} items to continue.', - maxSelectedCount: - 'You can only select up to {{maxCount}} items to continue.', - maxDate: - '{{field}} should not contain date after {{- maxDate}}', - minDate: - '{{field}} should not contain date before {{- minDate}}', - invalid_email: '{{field}} must be a valid email.', - invalid_url: '{{field}} must be a valid url.', - invalid_regex: - '{{field}} does not match the pattern {{regex}}.', - invalid_date: '{{field}} is not a valid date.', - invalid_day: '{{field}} is not a valid day.', - mask: '{{field}} does not match the mask.', - stripe: '{{stripe}}', - month: 'Month', - day: 'Day', - year: 'Year', - january: 'January', - february: 'February', - march: 'March', - april: 'April', - may: 'May', - june: 'June', - july: 'July', - august: 'August', - september: 'September', - october: 'October', - november: 'November', - december: 'December', - next: 'Next', - previous: 'Previous', - cancel: 'Cancel', - submit: 'Submit Form', - }, - }, - }, - }, - language: 'en', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - alwaysEnabled: false, - tableView: true, - key: 'lastName', - type: 'textfield', - input: true, - inDataGrid: true, - row: '0-1', - }, - ], - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - path: 'children', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - title: 'Guardian Information', - collapsible: false, - alwaysEnabled: false, - tableView: false, - key: 'guardianInformation', - type: 'panel', - input: false, - label: 'Panel', - components: [ - { - label: 'Guardian', - alwaysEnabled: false, - tableView: false, - key: 'guardian', - type: 'container', - input: true, - components: [ - { - label: 'First Name', - widget: { - i18n: { - lng: 'en', - resources: { - en: { - translation: { - complete: 'Submission Complete', - error: 'Please fix the following errors before submitting.', - required: '{{field}} is required', - pattern: - '{{field}} does not match the pattern {{pattern}}', - minLength: - '{{field}} must be longer than {{length}} characters.', - maxLength: - '{{field}} must be shorter than {{length}} characters.', - minWords: - '{{field}} must have more than {{length}} words.', - maxWords: - '{{field}} must have less than {{length}} words.', - min: '{{field}} cannot be less than {{min}}.', - max: '{{field}} cannot be greater than {{max}}.', - minSelectedCount: - 'You must select at least {{minCount}} items to continue.', - maxSelectedCount: - 'You can only select up to {{maxCount}} items to continue.', - maxDate: - '{{field}} should not contain date after {{- maxDate}}', - minDate: - '{{field}} should not contain date before {{- minDate}}', - invalid_email: '{{field}} must be a valid email.', - invalid_url: '{{field}} must be a valid url.', - invalid_regex: - '{{field}} does not match the pattern {{regex}}.', - invalid_date: '{{field}} is not a valid date.', - invalid_day: '{{field}} is not a valid day.', - mask: '{{field}} does not match the mask.', - stripe: '{{stripe}}', - month: 'Month', - day: 'Day', - year: 'Year', - january: 'January', - february: 'February', - march: 'March', - april: 'April', - may: 'May', - june: 'June', - july: 'July', - august: 'August', - september: 'September', - october: 'October', - november: 'November', - december: 'December', - next: 'Next', - previous: 'Previous', - cancel: 'Cancel', - submit: 'Submit Form', - }, - }, - }, - }, - language: 'en', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - alwaysEnabled: false, - tableView: true, - key: 'firstName1', - type: 'textfield', - input: true, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Last Name', - widget: { - i18n: { - lng: 'en', - resources: { - en: { - translation: { - complete: 'Submission Complete', - error: 'Please fix the following errors before submitting.', - required: '{{field}} is required', - pattern: - '{{field}} does not match the pattern {{pattern}}', - minLength: - '{{field}} must be longer than {{length}} characters.', - maxLength: - '{{field}} must be shorter than {{length}} characters.', - minWords: - '{{field}} must have more than {{length}} words.', - maxWords: - '{{field}} must have less than {{length}} words.', - min: '{{field}} cannot be less than {{min}}.', - max: '{{field}} cannot be greater than {{max}}.', - minSelectedCount: - 'You must select at least {{minCount}} items to continue.', - maxSelectedCount: - 'You can only select up to {{maxCount}} items to continue.', - maxDate: - '{{field}} should not contain date after {{- maxDate}}', - minDate: - '{{field}} should not contain date before {{- minDate}}', - invalid_email: '{{field}} must be a valid email.', - invalid_url: '{{field}} must be a valid url.', - invalid_regex: - '{{field}} does not match the pattern {{regex}}.', - invalid_date: '{{field}} is not a valid date.', - invalid_day: '{{field}} is not a valid day.', - mask: '{{field}} does not match the mask.', - stripe: '{{stripe}}', - month: 'Month', - day: 'Day', - year: 'Year', - january: 'January', - february: 'February', - march: 'March', - april: 'April', - may: 'May', - june: 'June', - july: 'July', - august: 'August', - september: 'September', - october: 'October', - november: 'November', - december: 'December', - next: 'Next', - previous: 'Previous', - cancel: 'Cancel', - submit: 'Submit Form', - }, - }, - }, - }, - language: 'en', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - alwaysEnabled: false, - tableView: true, - key: 'lastName1', - type: 'textfield', - input: true, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - path: 'guardian', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - path: 'guardianInformation', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Tabs', - components: [ - { - label: 'Tab 1', - key: 'tab1', - components: [ - { - label: 'One', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'one', - tab: 0, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Two', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'two', - tab: 0, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Tags', - alwaysEnabled: false, - tableView: false, - key: 'tags1', - type: 'tags', - input: true, - }, - ], - }, - { - label: 'Tab 2', - key: 'tab2', - components: [ - { - label: 'Three', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'three', - tab: 1, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Four', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'four', - tab: 1, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - }, - { - label: 'Tab 3', - key: 'tab3', - components: [ - { - label: 'Five', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'five', - tab: 2, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Six', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'six', - tab: 2, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - }, - ], - mask: false, - tableView: true, - alwaysEnabled: false, - type: 'tabs', - input: false, - key: 'tabs2', - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - path: 'tabs2', - }, - { - clearOnHide: false, - key: 'fieldset', - input: false, - tableView: false, - legend: 'Signature', - components: [ - { - key: 'fieldsetContent', - input: false, - html: '

This is some content

\n\n

Click the following if you agree to the rules.

\n\n
    \n\t
  • This
  • \n\t
  • is
  • \n\t
  • an
  • \n\t
  • important
  • \n\t
  • list
  • \n
\n', - type: 'content', - tableView: true, - label: 'Content', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'I agree to the rules', - dataGridLabel: false, - key: 'fieldsetIagreetotherules', - defaultValue: false, - type: 'checkbox', - tooltip: 'Check this if you agree.', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Signature', - key: 'fieldsetSignature', - type: 'signature', - hideLabel: true, - labelWidth: 30, - labelMargin: 3, - widget: null, - clearOnRefresh: false, - alwaysEnabled: false, - }, - ], - type: 'fieldset', - hideLabel: true, - label: 'Field Set', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - type: 'button', - label: 'Submit', - key: 'submit', - disableOnInvalid: true, - input: true, - tableView: true, - alwaysEnabled: false, - labelWidth: 30, - labelMargin: 3, - widget: null, - clearOnRefresh: false, - }, - ], - revisions: '', - _vid: 0, - title: 'Kitchen Sink', - display: 'form', - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', - }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - submissionAccess: [ - { roles: ['5692b920d1028f01000407e6'], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - settings: {}, - properties: {}, - name: 'kitchenSink', - path: 'kitchensink', - project: '5692b91fd1028f01000407e3', - created: '2019-09-12T13:06:58.622Z', - modified: '2021-06-16T15:03:39.596Z', - machineName: 'examples:kitchenSink', -}; -exports.otherForm = { - _id: '59121aaaed27e70083924f5b', - machineName: 'examples:e', - modified: '2021-06-08T21:04:52.339Z', - title: 'E', - display: 'form', - name: 'e', - path: 'e', - project: '5692b91fd1028f01000407e3', - created: '2017-05-09T19:38:18.503Z', - components: [ - { - key: 'content', - input: false, - html: '

You are on Page E!

\n', - type: 'content', - tableView: false, - label: 'Content', - }, - { - label: 'Total', - mask: false, - spellcheck: true, - disabled: true, - tableView: true, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - customDefaultValue: 'value = instance.root.data.score;', - calculateValue: { '+': [{ var: 'data.totalScore' }, { var: 'data.score' }] }, - key: 'total', - type: 'number', - inputType: 'number', - input: true, - }, - { - disabled: true, - type: 'number', - key: 'score', - label: 'Score', - inputType: 'number', - tableView: true, - input: true, - calculateValue: { - if: [ - { '==': [{ var: 'data.points' }, 'plus1'] }, - 1, - { '==': [{ var: 'data.points' }, 'plus2'] }, - 2, - { '==': [{ var: 'data.points' }, 'plus3'] }, - 3, - 0, - ], - }, - }, - { - input: true, - tableView: true, - label: 'Points', - key: 'points', - values: [ - { value: 'plus1', label: '+ 1' }, - { value: 'plus2', label: '+ 2' }, - { value: 'plus3', label: '+ 3' }, - { value: 'noChange', label: 'No Change' }, - ], - type: 'radio', - }, - { - input: true, - tableView: true, - label: 'Which page would you like to go to next?', - key: 'nextPage', - data: { - values: [ - { value: 'pageA', label: 'A' }, - { value: 'pageB', label: 'B' }, - { value: 'pageC', label: 'C' }, - { value: 'pageD', label: 'D' }, - { value: 'pageE', label: 'E' }, - { label: "I'm Done", value: 'done' }, - ], - }, - type: 'select', - lockKey: true, - }, - { input: true, label: 'Submit', tableView: false, key: 'submit', type: 'button' }, - ], - owner: '553dbfc08d22d5cb1a7024f2', - submissionAccess: [ - { roles: ['5692b920d1028f01000407e6'], type: 'create_all' }, - { roles: ['5692b920d1028f01000407e6'], type: 'read_all' }, - { roles: ['5692b920d1028f01000407e6'], type: 'update_all' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'create_own' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - access: [ - { roles: [], type: 'create_all' }, - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', - }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'create_own' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - tags: [], - type: 'form', - revisions: '', - _vid: 0, - settings: {}, -}; -exports.simpleNestedForm = { - display: 'form', - components: [ - { - collapsible: false, - key: 'panel', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Data Grid', - reorder: false, - addAnotherPosition: 'bottom', - layoutFixed: false, - enableRowGroups: false, - initEmpty: false, - tableView: false, - defaultValue: [{}], - key: 'dataGrid', - type: 'datagrid', - input: true, - components: [ - { - label: 'Required Field', - applyMaskOn: 'change', - tableView: true, - validate: { - required: true, - }, - key: 'requiredField', - type: 'textfield', - input: true, - }, - { - label: 'Maximum Length', - applyMaskOn: 'change', - tableView: true, - validate: { - maxLength: 5, - }, - key: 'maximumLength', - type: 'textfield', - input: true, - }, - { - label: 'Numbers Only', - applyMaskOn: 'change', - tableView: true, - validate: { - pattern: '\\d', - }, - key: 'numbersOnly', - type: 'textfield', - input: true, - }, - ], - }, - { - label: 'Two Validations', - applyMaskOn: 'change', - tableView: true, - validate: { - pattern: '\\d', - minLength: 5, - }, - key: 'twoValidations', - type: 'textfield', - input: true, - }, - ], - }, - { - type: 'button', - label: 'Submit', - key: 'submit', - disableOnInvalid: true, - input: true, - tableView: false, - }, - ], -}; diff --git a/src/process/validation/rules/__tests__/fixtures/forms.ts b/src/process/validation/rules/__tests__/fixtures/forms.ts index 5d5946a5..66bfe63c 100644 --- a/src/process/validation/rules/__tests__/fixtures/forms.ts +++ b/src/process/validation/rules/__tests__/fixtures/forms.ts @@ -1,359 +1,1799 @@ export const w4 = { - _id: '5994b43413a5f60007084c9f', - machineName: 'examples:w4', - modified: '2023-02-13T18:59:11.166Z', - title: 'W4', - display: 'pdf', - settings: { - pdf: { - id: '1ec0f8ee-6685-5d98-a847-26f67b67d6f0', - src: 'https://files.form.io/pdf/5692b91fd1028f01000407e3/file/1ec0f8ee-6685-5d98-a847-26f67b67d6f0', - }, + _id: '5994b43413a5f60007084c9f', + machineName: 'examples:w4', + modified: '2023-02-13T18:59:11.166Z', + title: 'W4', + display: 'pdf', + settings: { + pdf: { + id: '1ec0f8ee-6685-5d98-a847-26f67b67d6f0', + src: 'https://files.form.io/pdf/5692b91fd1028f01000407e3/file/1ec0f8ee-6685-5d98-a847-26f67b67d6f0', + }, + }, + name: 'w4', + path: 'w4', + project: '5692b91fd1028f01000407e3', + created: '2017-08-16T21:08:04.689Z', + components: [ + { + input: true, + tableView: true, + label: 'Office Code', + key: 'officeCode', + type: 'textfield', + overlay: { width: 121, height: 21, left: 656.344, top: 1319, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'e279pgyh', + }, + { + input: true, + tableView: true, + label: 'Employers Name and Address', + key: 'employersName', + type: 'textfield', + overlay: { + width: 570, + height: 21, + left: 79.34379999999999, + top: 1320, + page: 1, + style: '', + }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'ebh0ey', + }, + { + input: true, + tableView: true, + label: 'date', + key: 'date', + datePicker: { + datepickerMode: 'day', + showWeeks: true, + startingDay: 0, + initDate: '', + minMode: 'day', + maxMode: 'year', + yearRows: 4, + yearColumns: 5, + minDate: null, + maxDate: null, + }, + type: 'datetime', + overlay: { width: 176, height: 22, left: 842.344, top: 1275, page: 1, style: '' }, + widget: { + type: 'calendar', + displayInTimezone: 'viewer', + submissionTimezone: 'Europe/Paris', + locale: 'en', + useLocaleSettings: false, + allowInput: true, + mode: 'single', + enableTime: true, + noCalendar: false, + format: 'yyyy-MM-dd hh:mm a', + hourIncrement: 1, + minuteIncrement: 1, + time_24hr: false, + minDate: null, + maxDate: null, + }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: '', + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + format: 'yyyy-MM-dd hh:mm a', + useLocaleSettings: false, + allowInput: true, + enableDate: true, + enableTime: true, + defaultDate: '', + displayInTimezone: 'viewer', + timezone: '', + datepickerMode: 'day', + timePicker: { + hourStep: 1, + minuteStep: 1, + showMeridian: true, + readonlyInput: false, + mousewheel: true, + arrowkeys: true, + }, + customOptions: {}, + id: 'e38qzkb', + }, + { + input: true, + tableView: true, + label: 'Signature', + key: 'signature', + type: 'signature', + overlay: { width: 437, height: 41, left: 347.344, top: 1257, page: 1, style: '' }, + hideLabel: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + footer: 'Sign above', + width: '100%', + height: '150px', + penColor: 'black', + backgroundColor: 'rgb(245,245,235)', + minWidth: '0.5', + maxWidth: '2.5', + keepOverlayRatio: true, + id: 'ervvnoe', + }, + { + input: true, + tableView: true, + label: 'City, State, Zip', + key: 'cityStateZip', + type: 'textfield', + overlay: { width: 465, height: 21, left: 80.3438, top: 1084, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'e4x5zp', + }, + { + hideLabel: true, + overlay: { + page: 1, + top: 1027.8, + left: 730.538, + height: 12.75628779296875, + width: 11.400024414062523, + style: '', + }, + type: 'checkbox', + value: 'marriedsingle', + name: 'status', + defaultValue: false, + key: 'marriedButSingle', + datagridLabel: true, + label: 'Married But Single', + tableView: true, + inputType: 'radio', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'right', + description: '', + errorLabel: '', + tooltip: '', + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'eg81i4m', + }, + { + hideLabel: true, + overlay: { + page: 1, + top: 1027.4, + left: 652.938, + height: 13.618787792968659, + width: 13.400012207031228, + style: '', + }, + type: 'checkbox', + value: 'married', + name: 'status', + defaultValue: false, + key: 'married', + datagridLabel: true, + label: 'Married', + tableView: true, + inputType: 'radio', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'right', + description: '', + errorLabel: '', + tooltip: '', + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'efb089c', + }, + { + hideLabel: true, + overlay: { + page: 1, + top: 1027, + left: 576.538, + height: 13.88128779296875, + width: 13.400012207031205, + style: '', + }, + type: 'checkbox', + value: 'single', + name: 'status', + defaultValue: false, + key: 'single', + datagridLabel: true, + label: 'Single', + tableView: true, + inputType: 'radio', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'right', + description: '', + errorLabel: '', + tooltip: '', + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'emtvqvgq', + }, + { + overlay: { + page: 1, + top: 1044.2255555555555, + left: 81.30207777777777, + height: 21.10074501953125, + width: 466.72555555555556, + style: '', + }, + type: 'textfield', + key: 'homeAddress', + label: 'Home Address', + tableView: true, + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'ewtco6b', + }, + { + overlay: { + page: 1, + top: 998.6667777777777, + left: 789.0803333333333, + height: 23.47576724175342, + width: 234.0871314561631, + style: '', + }, + type: 'textfield', + key: 'ssn', + label: 'ssn', + inputMask: '999-99-9999', + tableView: true, + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'edz921k', + }, + { + overlay: { + page: 1, + top: 999.2222222222222, + left: 387.4138888888889, + height: 22.095556130642336, + width: 389.90500508626303, + style: '', + }, + type: 'textfield', + key: 'lastName', + label: 'Last Name', + tableView: true, + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'e2de7sa', + }, + { + overlay: { + page: 1, + top: 998.6664444444444, + left: 81.85761111111108, + height: 23.24826724175342, + width: 299.9064457160102, + style: '', + }, + type: 'textfield', + key: 'firstName', + label: 'First Name', + tableView: true, + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'eq3xm7d', + }, + { + overlay: { + page: 1, + top: 750.3336666666667, + left: 972.9684444444445, + height: '18', + width: '50', + style: '', + }, + type: 'textfield', + key: 'h', + label: 'H', + tableView: true, + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'ej8thdm', + }, + { + input: true, + tableView: true, + label: 'G', + key: 'g', + type: 'textfield', + overlay: { width: '50', height: '18', left: 973.172, top: 726.5, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'esj0u5e', + }, + { + input: true, + tableView: true, + label: 'F', + key: 'f', + type: 'textfield', + overlay: { width: '50', height: '18', left: 973.172, top: 621.5, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'e0kdkzp', }, - name: 'w4', - path: 'w4', - project: '5692b91fd1028f01000407e3', - created: '2017-08-16T21:08:04.689Z', - components: [ + { + input: true, + tableView: true, + label: 'E', + key: 'e', + type: 'textfield', + overlay: { width: '50', height: '18', left: 973.172, top: 599.5, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'e4wp06', + }, + { + input: true, + tableView: true, + label: 'D', + key: 'd', + type: 'textfield', + overlay: { width: '50', height: '18', left: 972.672, top: 577.5, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'evg04s8', + }, + { + input: true, + tableView: true, + label: 'C', + key: 'c', + type: 'textfield', + overlay: { width: '50', height: '18', left: 972.672, top: 556.5, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'e953emh', + }, + { + input: true, + tableView: true, + label: 'B', + key: 'b', + type: 'textfield', + overlay: { width: '50', height: '18', left: 972.672, top: 493, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'e2l0zzm', + }, + { + input: true, + tableView: true, + label: 'A', + key: 'a', + type: 'textfield', + overlay: { width: '50', height: '18', left: 972.469, top: 449.375, page: 1, style: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'egw3xvl', + }, + { + input: true, + label: 'Submit', + tableView: false, + key: 'submit', + type: 'button', + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + size: 'md', + leftIcon: '', + rightIcon: '', + block: false, + action: 'submit', + disableOnInvalid: false, + theme: 'primary', + id: 'etn79o', + }, + ], + owner: '553dbfc08d22d5cb1a7024f2', + submissionAccess: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { roles: [], type: 'read_all' }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + access: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { + roles: ['5692b920d1028f01000407e4', '5692b920d1028f01000407e5', '5692b920d1028f01000407e6'], + type: 'read_all', + }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + tags: [], + type: 'form', + _vid: 0, + revisions: '', +}; + +export const example = { + _id: '57aa1d2a5b7a477b002717fe', + machineName: 'examples:example', + modified: '2022-12-09T17:14:46.932Z', + title: 'Example', + display: 'form', + type: 'form', + name: 'example', + path: 'example', + project: '5692b91fd1028f01000407e3', + created: '2016-08-09T18:12:58.126Z', + components: [ + { + input: false, + html: '

Form.io Example Form

\n\n

This is a dynamically rendered JSON form built with Form.io. Using a simple drag-and-drop form builder, you can create any form that includes e-signatures, wysiwyg editors, date fields, layout components, data grids, surveys, etc.

\n', + type: 'content', + conditional: { show: '', when: null, eq: '' }, + key: 'content', + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + tableView: false, + modalEdit: false, + label: 'Content', + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + id: 'e4w5wnn', + addons: [], + }, + { + input: false, + columns: [ { - input: true, - tableView: true, - label: 'Office Code', - key: 'officeCode', - type: 'textfield', - overlay: { width: 121, height: 21, left: 656.344, top: 1319, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + components: [ + { + tabindex: '1', + tags: [], + clearOnHide: true, + hidden: false, + input: true, + tableView: true, + inputType: 'text', + inputMask: '', + label: 'First Name', + key: 'firstName', + placeholder: 'Enter your first name', + prefix: '', + suffix: '', + multiple: false, + defaultValue: '', + protected: false, + unique: false, + persistent: true, + validate: { required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, minLength: '', maxLength: '', pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e279pgyh', - }, - { - input: true, - tableView: true, - label: 'Employers Name and Address', - key: 'employersName', - type: 'textfield', - overlay: { - width: 570, - height: 21, - left: 79.34379999999999, - top: 1320, - page: 1, - style: '', - }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, custom: '', customPrivate: false, strictDateValidation: false, multiple: false, unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'ebh0ey', - }, - { - input: true, - tableView: true, - label: 'date', - key: 'date', - datePicker: { - datepickerMode: 'day', - showWeeks: true, - startingDay: 0, - initDate: '', - minMode: 'day', - maxMode: 'year', - yearRows: 4, - yearColumns: 5, - minDate: null, - maxDate: null, - }, - type: 'datetime', - overlay: { width: 176, height: 22, left: 842.344, top: 1275, page: 1, style: '' }, - widget: { - type: 'calendar', - displayInTimezone: 'viewer', - submissionTimezone: 'Europe/Paris', - locale: 'en', - useLocaleSettings: false, - allowInput: true, - mode: 'single', - enableTime: true, - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - hourIncrement: 1, - minuteIncrement: 1, - time_24hr: false, - minDate: null, - maxDate: null, + }, + conditional: { show: '', when: null, eq: '' }, + type: 'textfield', + customClass: '', + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + mask: false, + inputFormat: 'plain', + spellcheck: true, + id: 'ek1pl3', + addons: [], + displayMask: '', + truncateMultipleSpaces: false, }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: '', - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - attributes: {}, - validateOn: 'change', - validate: { + { + tabindex: '3', + tags: [], + clearOnHide: true, + hidden: false, + input: true, + tableView: true, + inputType: 'email', + label: 'Email', + key: 'email', + placeholder: 'Enter your email address', + prefix: '', + suffix: '', + defaultValue: '', + protected: false, + unique: false, + persistent: true, + type: 'email', + conditional: { show: '', when: null, eq: '' }, + kickbox: { enabled: false }, + customClass: '', + multiple: false, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, strictDateValidation: false, multiple: false, unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + mask: false, + inputFormat: 'plain', + inputMask: '', + spellcheck: true, + id: 'en2328', + addons: [], + displayMask: '', + truncateMultipleSpaces: false, }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - format: 'yyyy-MM-dd hh:mm a', - useLocaleSettings: false, - allowInput: true, - enableDate: true, - enableTime: true, - defaultDate: '', - displayInTimezone: 'viewer', - timezone: '', - datepickerMode: 'day', - timePicker: { - hourStep: 1, - minuteStep: 1, - showMeridian: true, - readonlyInput: false, - mousewheel: true, - arrowkeys: true, - }, - customOptions: {}, - id: 'e38qzkb', + ], + width: 6, + offset: 0, + push: 0, + pull: 0, + size: 'md', + currentWidth: 6, }, { - input: true, - tableView: true, - label: 'Signature', - key: 'signature', - type: 'signature', - overlay: { width: 437, height: 41, left: 347.344, top: 1257, page: 1, style: '' }, - hideLabel: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + components: [ + { + tabindex: '2', + tags: [], + clearOnHide: true, + hidden: false, + input: true, + tableView: true, + inputType: 'text', + inputMask: '', + label: 'Last Name', + key: 'lastName', + placeholder: 'Enter your last name', + prefix: '', + suffix: '', + multiple: false, + defaultValue: '', + protected: false, + unique: false, + persistent: true, + validate: { required: false, + minLength: '', + maxLength: '', + pattern: '', custom: '', customPrivate: false, strictDateValidation: false, multiple: false, unique: false, + }, + conditional: { show: '', when: null, eq: '' }, + type: 'textfield', + customClass: '', + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + mask: false, + inputFormat: 'plain', + spellcheck: true, + id: 'ex6xzd', + addons: [], + displayMask: '', + truncateMultipleSpaces: false, }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - footer: 'Sign above', - width: '100%', - height: '150px', - penColor: 'black', - backgroundColor: 'rgb(245,245,235)', - minWidth: '0.5', - maxWidth: '2.5', - keepOverlayRatio: true, - id: 'ervvnoe', - }, - { - input: true, - tableView: true, - label: 'City, State, Zip', - key: 'cityStateZip', - type: 'textfield', - overlay: { width: 465, height: 21, left: 80.3438, top: 1084, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + { + tabindex: '4', + tags: [], + clearOnHide: true, + hidden: false, + input: true, + tableView: true, + inputMask: '(999) 999-9999', + label: 'Phone Number', + key: 'phoneNumber', + placeholder: 'Enter your phone number', + prefix: '', + suffix: '', + multiple: false, + protected: false, + unique: false, + persistent: true, + defaultValue: '', + validate: { required: false, custom: '', customPrivate: false, @@ -363,483 +1803,1340 @@ export const w4 = { minLength: '', maxLength: '', pattern: '', + }, + type: 'phoneNumber', + conditional: { show: '', when: null, eq: '' }, + customClass: '', + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + mask: false, + inputType: 'tel', + inputFormat: 'plain', + spellcheck: true, + inputMode: 'decimal', + id: 'ecee6s', + addons: [], + displayMask: '', + truncateMultipleSpaces: false, }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e4x5zp', + ], + width: 6, + offset: 0, + push: 0, + pull: 0, + size: 'md', + currentWidth: 6, }, + ], + type: 'columns', + conditional: { show: '', when: null, eq: '' }, + key: 'columns', + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: false, + refreshOn: '', + redrawOn: '', + tableView: false, + modalEdit: false, + label: 'Columns', + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + tree: false, + autoAdjust: false, + id: 'e2i9r0c', + addons: [], + lazyLoad: false, + }, + { + tabindex: '5', + tags: [], + clearOnHide: true, + hidden: false, + input: true, + tableView: true, + label: 'Survey', + key: 'survey', + questions: [ { - hideLabel: true, - overlay: { - page: 1, - top: 1027.8, - left: 730.538, - height: 12.75628779296875, - width: 11.400024414062523, - style: '', - }, - type: 'checkbox', - value: 'marriedsingle', - name: 'status', - defaultValue: false, - key: 'marriedButSingle', - datagridLabel: true, - label: 'Married But Single', - tableView: true, - inputType: 'radio', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + value: 'howWouldYouRateTheFormIoPlatform', + label: 'How would you rate the Form.io platform?', + }, + { value: 'howWasCustomerSupport', label: 'How was Customer Support?' }, + { value: 'overallExperience', label: 'Overall Experience?' }, + ], + values: [ + { value: 'excellent', label: 'Excellent' }, + { value: 'great', label: 'Great' }, + { value: 'good', label: 'Good' }, + { value: 'average', label: 'Average' }, + { value: 'poor', label: 'Poor' }, + ], + defaultValue: '', + protected: false, + persistent: true, + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + type: 'survey', + conditional: { show: '', when: null, eq: '' }, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + unique: false, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + id: 'ek3vrnp', + addons: [], + }, + { + tags: [], + clearOnHide: true, + hidden: false, + input: true, + tableView: true, + label: 'Signature', + key: 'signature', + placeholder: '', + footer: 'Sign above', + width: '100%', + height: '150px', + penColor: 'black', + backgroundColor: 'rgb(245,245,235)', + minWidth: '0.5', + maxWidth: '2.5', + protected: false, + persistent: true, + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + type: 'signature', + hideLabel: true, + conditional: { show: '', when: null, eq: '' }, + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + unique: false, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + id: 'e4zac8j', + addons: [], + keepOverlayRatio: true, + }, + { + tabindex: '6', + conditional: { eq: '', when: null, show: '' }, + tags: [], + input: true, + label: 'Submit', + tableView: false, + key: 'submit', + size: 'md', + leftIcon: '', + rightIcon: '', + block: false, + action: 'submit', + disableOnInvalid: true, + theme: 'primary', + type: 'button', + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + id: 'et5j8rn', + addons: [], + }, + ], + owner: '554806425867f4ee203ea861', + submissionAccess: [ + { roles: ['5692b920d1028f01000407e6'], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { roles: [], type: 'read_all' }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + access: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { + roles: [ + '5692b920d1028f01000407e4', + '5692b920d1028f01000407e5', + '5692b920d1028f01000407e6', + '000000000000000000000000', + ], + type: 'read_all', + }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + tags: [], + _vid: 0, + revisions: '', +}; + +export const simpleForm = { + _id: '641b2ba3488ffcafa27c2e9f', + title: 'Simple Form', + name: 'simpleForm', + path: 'simpleform', + type: 'form', + display: 'form', + tags: [], + components: [ + { + label: 'Required Field', + applyMaskOn: 'change', + tableView: true, + validate: { + required: true, + }, + key: 'requiredField', + type: 'textfield', + input: true, + }, + { + label: 'Maximum Words', + applyMaskOn: 'change', + autoExpand: false, + tableView: true, + validate: { + maxWords: 4, + }, + key: 'maximumWords', + type: 'textarea', + input: true, + }, + { + label: 'Minimum Words', + applyMaskOn: 'change', + autoExpand: false, + tableView: true, + validate: { + minWords: 2, + }, + key: 'minimumWords', + type: 'textarea', + input: true, + }, + { + label: 'Email', + applyMaskOn: 'change', + tableView: true, + key: 'email', + type: 'email', + input: true, + }, + { + label: 'Url', + applyMaskOn: 'change', + tableView: true, + key: 'url', + type: 'url', + input: true, + }, + { + label: 'Input Mask', + applyMaskOn: 'change', + tableView: true, + key: 'inputMask', + type: 'phoneNumber', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { + type: 'input', + }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + minLength: '', + maxLength: '', + pattern: '', + }, + conditional: { + show: null, + when: null, + eq: '', + }, + overlay: { + style: '', + left: '', + top: '', + width: '', + height: '', + }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'tel', + inputFormat: 'plain', + inputMask: '(999) 999-9999', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + inputMode: 'decimal', + id: 'e8vls3a', + keyModified: true, + }, + { + type: 'button', + label: 'Submit', + key: 'submit', + disableOnInvalid: true, + input: true, + tableView: false, + }, + ], + settings: {}, + properties: {}, + project: '6419d8f2322509215938a9e6', + controller: '', + revisions: '', + submissionRevisions: '', + _vid: 0, + created: '2023-03-22T16:24:03.220Z', + modified: '2023-03-22T16:27:12.193Z', + machineName: 'qgvzeueerscrxbs:simpleForm', +}; + +export const wizard = { + _id: '578f930ef1912f8000459a50', + machineName: 'examples:wizard', + modified: '2022-11-17T20:30:28.519Z', + title: 'Wizard', + display: 'wizard', + type: 'form', + name: 'wizard', + path: 'wizard', + project: '5692b91fd1028f01000407e3', + created: '2016-07-20T15:04:46.906Z', + components: [ + { + key: 'page1', + input: false, + components: [ + { + type: 'textfield', + multiple: true, + key: 'textfieldonpage1', + label: 'Textfield on page 1', + tableView: true, + input: true, + }, + { + type: 'number', + validate: { required: true }, + defaultValue: 0, + key: 'numberField', + label: 'Number Field', + inputType: 'number', + tableView: true, + input: true, + }, + ], + title: 'First', + type: 'panel', + tableView: false, + label: 'Panel', + }, + { + tableView: false, + key: 'page2', + input: false, + components: [ + { + type: 'textfield', + validate: { required: true }, + key: 'textfieldonPage2', + label: 'Textfield on Page 2', + tableView: true, + input: true, + }, + { + input: true, + tableView: true, + label: 'Customer', + key: 'page2Customer', + placeholder: 'Select a customer', + data: { + url: 'https://examples.form.io/customer/submission', + headers: [{ value: '', key: '' }], + }, + dataSrc: 'url', + valueProperty: 'data.email', + template: '{{ item.data.firstName }} {{ item.data.lastName }}', + type: 'select', + widget: 'html5', + searchField: 'data.email', + }, + { + clearOnHide: false, + type: 'fieldset', + components: [ + { + type: 'textfield', + key: 'textfield', + label: 'Textfield', + tableView: true, + input: true, }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'eg81i4m', + ], + legend: 'FieldSet Label', + tableView: true, + input: false, + key: 'fieldSet', + label: 'Field Set', + }, + ], + title: 'Page 2', + type: 'panel', + label: 'Panel', + }, + { + type: 'panel', + components: [ + { + input: true, + tableView: true, + label: 'Text', + key: 'panelText', + validate: { required: true }, + type: 'textfield', }, { - hideLabel: true, - overlay: { - page: 1, - top: 1027.4, - left: 652.938, - height: 13.618787792968659, - width: 13.400012207031228, - style: '', + type: 'datagrid', + key: 'panelDataGrid', + label: 'Data Grid', + tableView: true, + components: [ + { + hideLabel: true, + type: 'textfield', + key: 'panelDataGridA', + label: 'A', + tableView: true, + input: true, + inDataGrid: true, }, - type: 'checkbox', - value: 'married', - name: 'status', - defaultValue: false, - key: 'married', - datagridLabel: true, - label: 'Married', - tableView: true, - inputType: 'radio', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + { + hideLabel: true, + type: 'textfield', + key: 'panelDataGridB', + label: 'B', + tableView: true, + input: true, + inDataGrid: true, }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'efb089c', + { + hideLabel: true, + type: 'textfield', + key: 'panelDataGridC', + label: 'C', + tableView: true, + input: true, + inDataGrid: true, + }, + { + hideLabel: true, + type: 'textfield', + key: 'panelDataGridD', + label: 'D', + tableView: true, + input: true, + inDataGrid: true, + }, + ], + input: true, }, { - hideLabel: true, - overlay: { - page: 1, - top: 1027, - left: 576.538, - height: 13.88128779296875, - width: 13.400012207031205, - style: '', - }, - type: 'checkbox', - value: 'single', - name: 'status', - defaultValue: false, - key: 'single', - datagridLabel: true, - label: 'Single', - tableView: true, - inputType: 'radio', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', + input: true, + tableView: true, + label: 'HTML5 Select', + key: 'panelHtml5Select', + data: { + values: [ + { value: 'orange', label: 'Orange' }, + { value: 'apple', label: 'Apple' }, + { value: 'banana', label: 'Banana' }, + { value: 'strawberry', label: 'Strawberry' }, + { value: 'kiwi', label: 'Kiwi' }, + ], + }, + widget: 'html5', + type: 'select', + }, + ], + tableView: false, + title: 'Page 3', + input: false, + key: 'panel', + label: 'Panel', + }, + { + key: 'page3', + input: false, + components: [ + { + type: 'textfield', + key: 'textfieldonPage3', + label: 'Textfield on Page 3', + tableView: true, + input: true, + }, + { + input: true, + tableView: true, + label: 'I agree to the follow the rules', + dataGridLabel: false, + key: 'page3Iagreetothefollowtherules', + defaultValue: false, + type: 'checkbox', + }, + { + input: true, + tableView: true, + label: 'Signature', + key: 'signature', + type: 'signature', + hideLabel: true, + lockKey: true, + }, + ], + title: 'Last', + type: 'panel', + tableView: false, + label: 'Panel', + }, + { + type: 'button', + disableOnInvalid: true, + key: 'submit', + tableView: false, + label: 'Submit', + input: true, + }, + ], + owner: '55673dc04f0405dd28205bb7', + submissionAccess: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { roles: ['5692b920d1028f01000407e6'], type: 'read_all' }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + access: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { + roles: ['5692b920d1028f01000407e4', '5692b920d1028f01000407e5', '5692b920d1028f01000407e6'], + type: 'read_all', + }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + tags: ['common'], + settings: { + controller: + "['$scope', function($scope) { $scope.$watch('submission.data', function(data) { console.log(data); }, true); }]", + }, + revisions: '', + _vid: 0, + controller: '', + properties: {}, +}; + +export const inlineEmbedFormPortal = { + _id: '617c032c68daf082ce063303', + type: 'form', + tags: [], + owner: '5e4aa9cf4037892ed27d5550', + components: [ + { + label: 'HTML', + tag: 'div', + attrs: [{ attr: '', value: '' }], + content: + "

Quick Inline Embed

\r\n

To quickly embed this form without using any framework, you can use the following code snippit and configure it using the Inline Embed Configuration form below.

\r\n

See our Inline Embed Documentation to know more about it.

", + refreshOnChange: false, + key: 'html1', + type: 'htmlelement', + input: false, + tableView: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'emraund', + }, + { + label: 'HTML', + tag: 'pre', + attrs: [{ attr: '', value: '' }], + content: + '', + refreshOnChange: true, + key: 'html', + type: 'htmlelement', + input: false, + tableView: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'e3wopjp', + }, + { + label: 'Copy to Clipboard', + action: 'custom', + showValidations: false, + theme: 'success', + block: true, + leftIcon: 'fa fa-copy', + tableView: false, + key: 'copyToClipboard', + type: 'button', + custom: + 'var embedCode = document.getElementById(\'embed-code\');\nif (embedCode) {\n embedCode.focus();\n embedCode.select();\n document.execCommand("copy");\n}', + input: true, + hideOnChildrenHidden: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + size: 'md', + rightIcon: '', + disableOnInvalid: false, + id: 'eq2y2ul', + }, + { + title: 'Inline Embed Configuration', + collapsible: false, + key: 'embedConfiguration', + type: 'panel', + label: 'Inline Embed Configuration', + input: false, + tableView: false, + components: [ + { + label: 'Embed Script', + customDefaultValue: "value = instance.options?.quickInlineEmbed || '';", + key: 'embed', + type: 'hidden', + tableView: true, + input: true, + mask: false, + inputType: 'text', + inputFormat: 'plain', + spellcheck: true, + hideOnChildrenHidden: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, multiple: false, - protected: false, unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'emtvqvgq', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'eq04647', }, { - overlay: { - page: 1, - top: 1044.2255555555555, - left: 81.30207777777777, - height: 21.10074501953125, - width: 466.72555555555556, - style: '', - }, - type: 'textfield', - key: 'homeAddress', - label: 'Home Address', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', + label: 'Project', + tableView: true, + key: 'project', + type: 'hidden', + input: true, + mask: false, + inputType: 'text', + inputFormat: 'plain', + spellcheck: true, + hideOnChildrenHidden: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, multiple: false, - defaultValue: null, - protected: false, unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'ewtco6b', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'eowdp4', }, { - overlay: { - page: 1, - top: 998.6667777777777, - left: 789.0803333333333, - height: 23.47576724175342, - width: 234.0871314561631, - style: '', - }, - type: 'textfield', - key: 'ssn', - label: 'ssn', - inputMask: '999-99-9999', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', + label: 'Base', + tableView: true, + key: 'base', + type: 'hidden', + input: true, + mask: false, + inputType: 'text', + inputFormat: 'plain', + spellcheck: true, + hideOnChildrenHidden: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, multiple: false, - defaultValue: null, - protected: false, unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'edz921k', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + id: 'e2ayb69', }, { - overlay: { - page: 1, - top: 999.2222222222222, - left: 387.4138888888889, - height: 22.095556130642336, - width: 389.90500508626303, - style: '', - }, - type: 'textfield', - key: 'lastName', - label: 'Last Name', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', + label: 'Form Url', + customDefaultValue: "value = instance.options?.embedFormSrc || '';", + key: 'src', + type: 'hidden', + input: true, + tableView: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, multiple: false, - defaultValue: null, - protected: false, unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e2de7sa', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + inputType: 'hidden', + id: 'ep1qgx', }, { - overlay: { - page: 1, - top: 998.6664444444444, - left: 81.85761111111108, - height: 23.24826724175342, - width: 299.9064457160102, - style: '', - }, - type: 'textfield', - key: 'firstName', - label: 'First Name', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', + label: 'Template', + widget: 'choicesjs', + tableView: true, + data: { + values: [ + { label: 'Boostrap 4', value: 'false' }, + { label: 'USWDS', value: 'uswds' }, + ], + json: '', + url: '', + resource: '', + custom: '', + }, + key: 'template', + type: 'select', + input: true, + hideOnChildrenHidden: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, multiple: false, - defaultValue: null, - protected: false, unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + onlyAvailableItems: false, + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + idPath: 'id', + clearOnRefresh: false, + limit: 100, + dataSrc: 'values', + valueProperty: '', + lazyLoad: true, + filter: '', + searchEnabled: true, + searchDebounce: 0.3, + searchField: '', + minSearch: 0, + readOnlyValue: false, + authenticate: false, + ignoreCache: false, + template: '{{ item.label }}', + selectFields: '', + selectThreshold: 0.3, + uniqueOptions: false, + fuseOptions: { include: 'score', threshold: 0.3 }, + indexeddb: { filter: {} }, + customOptions: {}, + useExactSearch: false, + id: 'ewk9iop', + }, + { + title: 'Advanced Settings', + collapsible: true, + key: 'advancedSettings', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ + { + label: 'Redirect', + tooltip: 'The URL you would like to redirect to after the form is submitted. ', + tableView: true, + key: 'redirect', + type: 'url', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, @@ -849,69 +3146,63 @@ export const w4 = { minLength: '', maxLength: '', pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'url', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'et7ayx', }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'eq3xm7d', - }, - { - overlay: { - page: 1, - top: 750.3336666666667, - left: 972.9684444444445, - height: '18', - width: '50', - style: '', - }, - type: 'textfield', - key: 'h', - label: 'H', - tableView: true, - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + { + label: 'Submission Endpoint', + tooltip: + 'The endpoint you would like to POST the submission toward. This allows you to send the submission to endpoints other than the default submission endpoint.', + tableView: true, + key: 'submit', + type: 'url', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, @@ -921,192 +3212,186 @@ export const w4 = { minLength: '', maxLength: '', pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'url', + inputFormat: 'plain', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + id: 'epa9s3i', }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'ej8thdm', - }, - { - input: true, - tableView: true, - label: 'G', - key: 'g', - type: 'textfield', - overlay: { width: '50', height: '18', left: 973.172, top: 726.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + { + label: 'Inherit Page CSS', + tooltip: + 'When it is unchecked, it loads all dependent CSS libraries to render the form.', + tableView: false, + defaultValue: false, + calculateValue: 'if (data.encapsulate) {\n value = true;\n}', + key: 'inherit', + type: 'checkbox', + input: true, + calculateValueMode: 'json', + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'right', + description: '', + errorLabel: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, strictDateValidation: false, multiple: false, unique: false, - minLength: '', - maxLength: '', - pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + inputType: 'checkbox', + value: '', + name: '', + id: 'e23lxjq', }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'esj0u5e', - }, - { - input: true, - tableView: true, - label: 'F', - key: 'f', - type: 'textfield', - overlay: { width: '50', height: '18', left: 973.172, top: 621.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + { + label: 'Debug Mode', + tooltip: + 'Add a number of console.log records to the browser on how this form is progressing through the embedding code.', + tableView: false, + defaultValue: false, + key: 'debug', + type: 'checkbox', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: true, + labelPosition: 'right', + description: '', + errorLabel: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, strictDateValidation: false, multiple: false, unique: false, - minLength: '', - maxLength: '', - pattern: '', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + inputType: 'checkbox', + value: '', + name: '', + id: 'eh4hyc', }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e0kdkzp', - }, - { - input: true, - tableView: true, - label: 'E', - key: 'e', - type: 'textfield', - overlay: { width: '50', height: '18', left: 973.172, top: 599.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + { + label: 'Custom Configurations', + description: + 'The following FormioConfig parameters can be specified: config, form, submission, libs.\n

Example:\n { "config": { "readOnly": true } }.\n
Click here for more examples.\n

\n', + tooltip: + 'Add configuration in JSON format for the global FormioConfig variable to control the embedded flow', + editor: 'ace', + autoExpand: false, + tableView: true, + key: 'config', + type: 'textarea', + as: 'json', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + errorLabel: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, @@ -1116,62 +3401,71 @@ export const w4 = { minLength: '', maxLength: '', pattern: '', + minWords: '', + maxWords: '', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'html', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + rows: 3, + wysiwyg: false, + fixedSize: true, + id: 'elmjv3ki', }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e4wp06', - }, - { - input: true, - tableView: true, - label: 'D', - key: 'd', - type: 'textfield', - overlay: { width: '50', height: '18', left: 972.672, top: 577.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + { + label: 'Before Render Handler', + description: + 'The callback accepts the following parameters: Formio, element, config. \n

Example:\nfunction(Formio, element, config) { console.log(Formio, element, config); }\n

', + tooltip: 'Provide a callback that is executed before the Form is rendered.', + editor: 'ace', + autoExpand: false, + tableView: true, + key: 'before', + type: 'textarea', + as: 'string', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + errorLabel: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, @@ -1181,62 +3475,71 @@ export const w4 = { minLength: '', maxLength: '', pattern: '', + minWords: '', + maxWords: '', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'html', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + rows: 3, + wysiwyg: false, + fixedSize: true, + id: 'ekd4ovh', }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'evg04s8', - }, - { - input: true, - tableView: true, - label: 'C', - key: 'c', - type: 'textfield', - overlay: { width: '50', height: '18', left: 972.672, top: 556.5, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { + { + label: 'After Render Handler', + description: + 'The callback accepts instance variable as a parameter.\n

Example: function(instance) { console.log(instance); }\n

', + tooltip: 'Provide a callback that is called after the form is done rendering.', + editor: 'ace', + autoExpand: false, + tableView: true, + key: 'after', + type: 'textarea', + as: 'string', + input: true, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + errorLabel: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: { type: 'input' }, + attributes: {}, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false, @@ -1246,4697 +3549,2332 @@ export const w4 = { minLength: '', maxLength: '', pattern: '', + minWords: '', + maxWords: '', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + mask: false, + inputType: 'text', + inputFormat: 'html', + inputMask: '', + displayMask: '', + spellcheck: true, + truncateMultipleSpaces: false, + rows: 3, + wysiwyg: false, + fixedSize: true, + id: 'eiqb29', }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e953emh', - }, - { - input: true, - tableView: true, - label: 'B', - key: 'b', - type: 'textfield', - overlay: { width: '50', height: '18', left: 972.672, top: 493, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', + ], + collapsed: true, + hideOnChildrenHidden: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: false, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, multiple: false, - defaultValue: null, - protected: false, unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'e2l0zzm', + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + tree: false, + lazyLoad: false, + theme: 'default', + breadcrumb: 'default', + id: 'e71fwgr', }, + ], + hideOnChildrenHidden: false, + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: false, + hidden: false, + clearOnHide: false, + refreshOn: '', + redrawOn: '', + modalEdit: false, + dataGridLabel: false, + labelPosition: 'top', + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + calculateServer: false, + widget: null, + attributes: {}, + validateOn: 'change', + validate: { + required: false, + custom: '', + customPrivate: false, + strictDateValidation: false, + multiple: false, + unique: false, + }, + conditional: { show: null, when: null, eq: '' }, + overlay: { style: '', left: '', top: '', width: '', height: '' }, + allowCalculateOverride: false, + encrypted: false, + showCharCount: false, + showWordCount: false, + properties: {}, + allowMultipleMasks: false, + addons: [], + tree: false, + lazyLoad: false, + theme: 'default', + breadcrumb: 'default', + id: 'e8be5t4', + }, + ], + revisions: 'current', + _vid: 4, + title: 'Inline Embed Form - Portal', + display: 'form', + access: [ + { + roles: ['5692b920d1028f01000407e4', '5692b920d1028f01000407e5', '5692b920d1028f01000407e6'], + type: 'read_all', + }, + ], + submissionAccess: [], + controller: '', + properties: {}, + settings: {}, + name: 'inlineEmbedFormPortal', + path: 'inlineembedformportal', + project: '5692b91fd1028f01000407e3', + created: '2021-10-29T14:20:28.581Z', + modified: '2022-11-17T15:09:31.641Z', + machineName: 'examples:inlineEmbedFormPortal', +}; + +export const validationRulesNyHealth = { + _id: '617051c6a8135f6a0780c364', + type: 'form', + tags: [], + owner: '5d921ec842af9789e5b81b26', + components: [ + { + title: 'Case 1', + collapsible: false, + key: 'case1', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - input: true, - tableView: true, - label: 'A', - key: 'a', - type: 'textfield', - overlay: { width: '50', height: '18', left: 972.469, top: 449.375, page: 1, style: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'egw3xvl', + label: 'HTML', + attrs: [{ attr: '', value: '' }], + content: + '

Case 1:

\n

Box a value can not differ by a factor(.5) of n from Box b

\n• EX: 100(b) -> a(max)50', + refreshOnChange: false, + key: 'html1', + type: 'htmlelement', + input: false, + tableView: false, }, { - input: true, - label: 'Submit', - tableView: false, - key: 'submit', - type: 'button', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - size: 'md', - leftIcon: '', - rightIcon: '', - block: false, - action: 'submit', - disableOnInvalid: false, - theme: 'primary', - id: 'etn79o', + label: 'Box a', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + validate: { + customMessage: 'Needs to be within the range. ', + custom: 'valid = input >= (data.boxB * 0.5) && input <= (data.boxB * 1.5);', + }, + errorLabel: 'Box A Value', + key: 'boxA', + type: 'number', + input: true, }, - ], - owner: '553dbfc08d22d5cb1a7024f2', - submissionAccess: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', + label: 'Box b', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + key: 'boxB', + type: 'number', + input: true, }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - tags: [], - type: 'form', - _vid: 0, - revisions: '', -}; - -export const example = { - _id: '57aa1d2a5b7a477b002717fe', - machineName: 'examples:example', - modified: '2022-12-09T17:14:46.932Z', - title: 'Example', - display: 'form', - type: 'form', - name: 'example', - path: 'example', - project: '5692b91fd1028f01000407e3', - created: '2016-08-09T18:12:58.126Z', - components: [ + ], + }, + { + title: 'Case 2 / Case 3', + collapsible: false, + key: 'case2', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - input: false, - html: '

Form.io Example Form

\n\n

This is a dynamically rendered JSON form built with Form.io. Using a simple drag-and-drop form builder, you can create any form that includes e-signatures, wysiwyg editors, date fields, layout components, data grids, surveys, etc.

\n', - type: 'content', - conditional: { show: '', when: null, eq: '' }, - key: 'content', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - tableView: false, - modalEdit: false, - label: 'Content', - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - id: 'e4w5wnn', - addons: [], + label: 'HTML', + attrs: [{ attr: '', value: '' }], + content: + '

Case 2:

\n

Box b must compare the value on the number of repeating section

\n• Value of b must match the amount of repeating section
\n• Number of repeating sections must not exceed value of b\n\n

Case 3:

\n

Box b in a repeating section 1a must be unique in all repeating section

', + refreshOnChange: false, + key: 'html', + type: 'htmlelement', + input: false, + tableView: false, }, { - input: false, - columns: [ - { - components: [ - { - tabindex: '1', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - inputType: 'text', - inputMask: '', - label: 'First Name', - key: 'firstName', - placeholder: 'Enter your first name', - prefix: '', - suffix: '', - multiple: false, - defaultValue: '', - protected: false, - unique: false, - persistent: true, - validate: { - required: false, - minLength: '', - maxLength: '', - pattern: '', - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: '', when: null, eq: '' }, - type: 'textfield', - customClass: '', - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputFormat: 'plain', - spellcheck: true, - id: 'ek1pl3', - addons: [], - displayMask: '', - truncateMultipleSpaces: false, - }, - { - tabindex: '3', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - inputType: 'email', - label: 'Email', - key: 'email', - placeholder: 'Enter your email address', - prefix: '', - suffix: '', - defaultValue: '', - protected: false, - unique: false, - persistent: true, - type: 'email', - conditional: { show: '', when: null, eq: '' }, - kickbox: { enabled: false }, - customClass: '', - multiple: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputFormat: 'plain', - inputMask: '', - spellcheck: true, - id: 'en2328', - addons: [], - displayMask: '', - truncateMultipleSpaces: false, - }, - ], - width: 6, - offset: 0, - push: 0, - pull: 0, - size: 'md', - currentWidth: 6, - }, - { - components: [ - { - tabindex: '2', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - inputType: 'text', - inputMask: '', - label: 'Last Name', - key: 'lastName', - placeholder: 'Enter your last name', - prefix: '', - suffix: '', - multiple: false, - defaultValue: '', - protected: false, - unique: false, - persistent: true, - validate: { - required: false, - minLength: '', - maxLength: '', - pattern: '', - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: '', when: null, eq: '' }, - type: 'textfield', - customClass: '', - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputFormat: 'plain', - spellcheck: true, - id: 'ex6xzd', - addons: [], - displayMask: '', - truncateMultipleSpaces: false, - }, - { - tabindex: '4', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - inputMask: '(999) 999-9999', - label: 'Phone Number', - key: 'phoneNumber', - placeholder: 'Enter your phone number', - prefix: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - defaultValue: '', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - type: 'phoneNumber', - conditional: { show: '', when: null, eq: '' }, - customClass: '', - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: 'tel', - inputFormat: 'plain', - spellcheck: true, - inputMode: 'decimal', - id: 'ecee6s', - addons: [], - displayMask: '', - truncateMultipleSpaces: false, - }, - ], - width: 6, - offset: 0, - push: 0, - pull: 0, - size: 'md', - currentWidth: 6, - }, - ], - type: 'columns', - conditional: { show: '', when: null, eq: '' }, - key: 'columns', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: false, - refreshOn: '', - redrawOn: '', - tableView: false, - modalEdit: false, - label: 'Columns', - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - tree: false, - autoAdjust: false, - id: 'e2i9r0c', - addons: [], - lazyLoad: false, + label: 'Box b', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + calculateValue: + "var dataGrid = instance.root.getComponent('dataGrid');\ndataGrid.component.validate.minLength = parseInt(value, 10);\ndataGrid.component.validate.maxLength = parseInt(value, 10);\ninstance.root.redraw();", + key: 'boxB1', + type: 'number', + input: true, }, { - tabindex: '5', - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - label: 'Survey', - key: 'survey', - questions: [ - { - value: 'howWouldYouRateTheFormIoPlatform', - label: 'How would you rate the Form.io platform?', - }, - { value: 'howWasCustomerSupport', label: 'How was Customer Support?' }, - { value: 'overallExperience', label: 'Overall Experience?' }, - ], - values: [ - { value: 'excellent', label: 'Excellent' }, - { value: 'great', label: 'Great' }, - { value: 'good', label: 'Good' }, - { value: 'average', label: 'Average' }, - { value: 'poor', label: 'Poor' }, - ], - defaultValue: '', - protected: false, - persistent: true, - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + label: 'Data Grid', + reorder: false, + addAnotherPosition: 'bottom', + layoutFixed: false, + enableRowGroups: false, + initEmpty: false, + tableView: false, + defaultValue: [{ uniqueName: '' }], + key: 'dataGrid', + type: 'datagrid', + input: true, + components: [ + { + label: 'Unique Name', + tableView: true, + unique: true, + key: 'uniqueName', + type: 'textfield', + input: true, }, - type: 'survey', - conditional: { show: '', when: null, eq: '' }, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - unique: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - id: 'ek3vrnp', - addons: [], + ], }, + ], + breadcrumbClickable: true, + buttonSettings: { previous: true, cancel: true, next: true }, + scrollToTop: false, + }, + { + title: 'Case 4', + collapsible: false, + key: 'case7', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - tags: [], - clearOnHide: true, - hidden: false, - input: true, - tableView: true, - label: 'Signature', - key: 'signature', - placeholder: '', - footer: 'Sign above', - width: '100%', - height: '150px', - penColor: 'black', - backgroundColor: 'rgb(245,245,235)', - minWidth: '0.5', - maxWidth: '2.5', - protected: false, - persistent: true, - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - type: 'signature', - hideLabel: true, - conditional: { show: '', when: null, eq: '' }, - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - unique: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - id: 'e4zac8j', - addons: [], - keepOverlayRatio: true, + label: 'HTML', + attrs: [{ attr: '', value: '' }], + content: + '

Case 4:

\n

Box b in a repeating section a1 must be greater then Box b in repeating section a2.

', + refreshOnChange: false, + key: 'html2', + type: 'htmlelement', + input: false, + tableView: false, }, { - tabindex: '6', - conditional: { eq: '', when: null, show: '' }, - tags: [], - input: true, - label: 'Submit', - tableView: false, - key: 'submit', - size: 'md', - leftIcon: '', - rightIcon: '', - block: false, - action: 'submit', - disableOnInvalid: true, - theme: 'primary', - type: 'button', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + title: 'Case 4.1', + collapsible: false, + key: 'case4', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ + { + label: 'Number1', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + key: 'number1', + type: 'number', + input: true, }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - id: 'et5j8rn', - addons: [], + ], }, - ], - owner: '554806425867f4ee203ea861', - submissionAccess: [ - { roles: ['5692b920d1028f01000407e6'], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - '000000000000000000000000', - ], - type: 'read_all', - }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - tags: [], - _vid: 0, - revisions: '', -}; - -export const simpleForm = { - _id: '641b2ba3488ffcafa27c2e9f', - title: 'Simple Form', - name: 'simpleForm', - path: 'simpleform', - type: 'form', - display: 'form', - tags: [], - components: [ - { - label: 'Required Field', - applyMaskOn: 'change', - tableView: true, - validate: { - required: true, + title: 'Case 4.2', + collapsible: false, + key: 'case42', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ + { + label: 'Number2', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + validate: { + customMessage: 'Value must be greater than or equal to Number1', + custom: 'valid = input>=data.number1;', + }, + key: 'number2', + type: 'number', + input: true, }, - key: 'requiredField', - type: 'textfield', - input: true, + ], }, + ], + }, + { + title: 'Case 5', + collapsible: false, + key: 'case5', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - label: 'Maximum Words', - applyMaskOn: 'change', - autoExpand: false, - tableView: true, - validate: { - maxWords: 4, - }, - key: 'maximumWords', - type: 'textarea', - input: true, + label: 'HTML', + attrs: [{ attr: '', value: '' }], + content: + '

Case 5:

\n

Box b in a repeating section a1 must be greater than Box c in repeating section a1. and also it can be applied to fields outside repeating section

\n', + refreshOnChange: false, + key: 'html3', + type: 'htmlelement', + input: false, + tableView: false, }, { - label: 'Minimum Words', - applyMaskOn: 'change', - autoExpand: false, - tableView: true, - validate: { - minWords: 2, + label: 'Data Grid', + reorder: false, + addAnotherPosition: 'bottom', + layoutFixed: false, + enableRowGroups: false, + initEmpty: false, + tableView: false, + defaultValue: [{}], + key: 'dataGrid1', + type: 'datagrid', + input: true, + components: [ + { + label: 'Number3', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + key: 'number3', + type: 'number', + input: true, }, - key: 'minimumWords', - type: 'textarea', - input: true, - }, - { - label: 'Email', - applyMaskOn: 'change', - tableView: true, - key: 'email', - type: 'email', - input: true, + { + label: 'Number4', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + validate: { + customMessage: 'must be greater than the value in Number3', + custom: 'valid = input>row.number3;\n', + }, + errorLabel: 'Number4', + key: 'number4', + type: 'number', + input: true, + }, + ], }, { - label: 'Url', - applyMaskOn: 'change', - tableView: true, - key: 'url', - type: 'url', - input: true, + title: 'Case 5 - Number outside of Section', + tooltip: + 'This is dependent on which value in the repeating section above would need to be validated against.', + collapsible: false, + key: 'case5NumberOutsideOfSection1', + type: 'panel', + label: 'Case 5 - Number outside of Section', + input: false, + tableView: false, + components: [ + { + label: 'Number5', + mask: false, + tableView: false, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + validate: { + customMessage: 'Value must be greater than Number3', + custom: 'valid = input>data.number3;', + }, + key: 'number6', + type: 'number', + input: true, + }, + ], }, + ], + }, + { + title: 'Case 6 - Min / Max Date from Today', + collapsible: false, + key: 'case6', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - label: 'Input Mask', - applyMaskOn: 'change', - tableView: true, - key: 'inputMask', - type: 'phoneNumber', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { - type: 'input', - }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { - show: null, - when: null, - eq: '', - }, - overlay: { - style: '', - left: '', - top: '', - width: '', - height: '', - }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'tel', - inputFormat: 'plain', - inputMask: '(999) 999-9999', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - inputMode: 'decimal', - id: 'e8vls3a', - keyModified: true, + label: 'HTML', + attrs: [{ attr: '', value: '' }], + content: + '

Case 6:

\n

Date field d should have a date that is at most/least N days/weeks/months/years ago/ from today\n \n

', + refreshOnChange: false, + key: 'html4', + type: 'htmlelement', + input: false, + tableView: false, }, { - type: 'button', - label: 'Submit', - key: 'submit', - disableOnInvalid: true, - input: true, - tableView: false, + label: 'Date / Time', + tableView: false, + enableMinDateInput: true, + datePicker: { + disableWeekends: false, + disableWeekdays: false, + maxDate: "moment().add(10, 'days')", + minDate: "moment().subtract(10, 'days')", + }, + enableMaxDateInput: true, + key: 'dateTime', + type: 'datetime', + input: true, + widget: { + type: 'calendar', + displayInTimezone: 'viewer', + locale: 'en', + useLocaleSettings: false, + allowInput: true, + mode: 'single', + enableTime: true, + noCalendar: false, + format: 'yyyy-MM-dd hh:mm a', + hourIncrement: 1, + minuteIncrement: 1, + time_24hr: false, + minDate: "moment().subtract(10, 'days')", + disableWeekends: false, + disableWeekdays: false, + maxDate: "moment().add(10, 'days')", + }, }, - ], - settings: {}, - properties: {}, - project: '6419d8f2322509215938a9e6', - controller: '', - revisions: '', - submissionRevisions: '', - _vid: 0, - created: '2023-03-22T16:24:03.220Z', - modified: '2023-03-22T16:27:12.193Z', - machineName: 'qgvzeueerscrxbs:simpleForm', + ], + }, + { + type: 'button', + label: 'Submit', + key: 'submit', + disableOnInvalid: true, + input: true, + tableView: false, + }, + ], + revisions: '', + _vid: 0, + title: 'Validation Rules - NY Health', + display: 'wizard', + access: [ + { + roles: ['5692b920d1028f01000407e4', '5692b920d1028f01000407e5', '5692b920d1028f01000407e6'], + type: 'read_all', + }, + ], + submissionAccess: [], + controller: '', + properties: {}, + settings: {}, + name: 'validationRulesNyHealth', + path: 'validationrulesnyhealth', + project: '5692b91fd1028f01000407e3', + created: '2021-10-20T17:28:38.165Z', + modified: '2021-10-20T18:08:13.287Z', + machineName: 'examples:validationRulesNyHealth', }; -export const wizard = { - _id: '578f930ef1912f8000459a50', - machineName: 'examples:wizard', - modified: '2022-11-17T20:30:28.519Z', - title: 'Wizard', - display: 'wizard', - type: 'form', - name: 'wizard', - path: 'wizard', - project: '5692b91fd1028f01000407e3', - created: '2016-07-20T15:04:46.906Z', - components: [ - { - key: 'page1', - input: false, - components: [ - { - type: 'textfield', - multiple: true, - key: 'textfieldonpage1', - label: 'Textfield on page 1', - tableView: true, - input: true, - }, - { - type: 'number', - validate: { required: true }, - defaultValue: 0, - key: 'numberField', - label: 'Number Field', - inputType: 'number', - tableView: true, - input: true, - }, - ], - title: 'First', - type: 'panel', - tableView: false, - label: 'Panel', - }, +export const inlineembed = { + _id: '60089c6795f584688609f83c', + type: 'form', + tags: [], + owner: '553dbfc08d22d5cb1a7024f2', + components: [ + { + html: '

This is a form that enables the configuration of a Quick Inline Embed for a Form.io form.

For advanced documentation on how to use this embedding feature, please see our Quick Inline Embed Documentation.

', + label: 'Content', + refreshOnChange: false, + key: 'content', + type: 'content', + input: false, + tableView: false, + }, + { + label: 'Columns', + columns: [ { - tableView: false, - key: 'page2', - input: false, - components: [ + components: [ + { + title: 'Embed Configuration', + collapsible: false, + key: 'embedConfiguration', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - type: 'textfield', - validate: { required: true }, - key: 'textfieldonPage2', - label: 'Textfield on Page 2', - tableView: true, - input: true, + label: 'Embed Script', + defaultValue: 'https://cdn.form.io/formiojs/formio.embed.js', + key: 'embed', + type: 'hidden', + tableView: true, + input: true, + mask: false, + inputType: 'text', + inputFormat: 'plain', + spellcheck: true, + hideOnChildrenHidden: false, }, { - input: true, - tableView: true, - label: 'Customer', - key: 'page2Customer', - placeholder: 'Select a customer', - data: { - url: 'https://examples.form.io/customer/submission', - headers: [{ value: '', key: '' }], - }, - dataSrc: 'url', - valueProperty: 'data.email', - template: '{{ item.data.firstName }} {{ item.data.lastName }}', - type: 'select', - widget: 'html5', - searchField: 'data.email', + label: 'Project', + tableView: true, + key: 'project', + type: 'hidden', + input: true, + mask: false, + inputType: 'text', + inputFormat: 'plain', + spellcheck: true, + hideOnChildrenHidden: false, }, { - clearOnHide: false, - type: 'fieldset', - components: [ - { - type: 'textfield', - key: 'textfield', - label: 'Textfield', - tableView: true, - input: true, - }, - ], - legend: 'FieldSet Label', - tableView: true, - input: false, - key: 'fieldSet', - label: 'Field Set', + label: 'Base', + tableView: true, + key: 'base', + type: 'hidden', + input: true, + mask: false, + inputType: 'text', + inputFormat: 'plain', + spellcheck: true, + hideOnChildrenHidden: false, }, - ], - title: 'Page 2', - type: 'panel', - label: 'Panel', - }, - { - type: 'panel', - components: [ { - input: true, - tableView: true, - label: 'Text', - key: 'panelText', - validate: { required: true }, - type: 'textfield', + label: 'Form URL', + tableView: true, + validate: { required: true }, + key: 'src', + type: 'textfield', + input: true, + defaultValue: 'https://examples.form.io/example', + hideOnChildrenHidden: false, }, { - type: 'datagrid', - key: 'panelDataGrid', - label: 'Data Grid', - tableView: true, - components: [ - { - hideLabel: true, - type: 'textfield', - key: 'panelDataGridA', - label: 'A', - tableView: true, - input: true, - inDataGrid: true, - }, - { - hideLabel: true, - type: 'textfield', - key: 'panelDataGridB', - label: 'B', - tableView: true, - input: true, - inDataGrid: true, - }, - { - hideLabel: true, - type: 'textfield', - key: 'panelDataGridC', - label: 'C', - tableView: true, - input: true, - inDataGrid: true, - }, - { - hideLabel: true, - type: 'textfield', - key: 'panelDataGridD', - label: 'D', - tableView: true, - input: true, - inDataGrid: true, - }, + label: 'Template', + widget: 'choicesjs', + tableView: true, + data: { + values: [ + { label: 'Boostrap 4', value: 'false' }, + { label: 'USWDS', value: 'uswds' }, ], - input: true, + }, + key: 'template', + type: 'select', + input: true, + searchThreshold: 0.3, + hideOnChildrenHidden: false, }, { - input: true, - tableView: true, - label: 'HTML5 Select', - key: 'panelHtml5Select', - data: { - values: [ - { value: 'orange', label: 'Orange' }, - { value: 'apple', label: 'Apple' }, - { value: 'banana', label: 'Banana' }, - { value: 'strawberry', label: 'Strawberry' }, - { value: 'kiwi', label: 'Kiwi' }, - ], - }, - widget: 'html5', - type: 'select', - }, - ], - tableView: false, - title: 'Page 3', - input: false, - key: 'panel', - label: 'Panel', - }, - { - key: 'page3', - input: false, - components: [ - { - type: 'textfield', - key: 'textfieldonPage3', - label: 'Textfield on Page 3', - tableView: true, - input: true, - }, - { - input: true, - tableView: true, - label: 'I agree to the follow the rules', - dataGridLabel: false, - key: 'page3Iagreetothefollowtherules', - defaultValue: false, - type: 'checkbox', - }, - { - input: true, - tableView: true, - label: 'Signature', - key: 'signature', - type: 'signature', - hideLabel: true, - lockKey: true, - }, - ], - title: 'Last', - type: 'panel', - tableView: false, - label: 'Panel', - }, - { - type: 'button', - disableOnInvalid: true, - key: 'submit', - tableView: false, - label: 'Submit', - input: true, - }, - ], - owner: '55673dc04f0405dd28205bb7', - submissionAccess: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: ['5692b920d1028f01000407e6'], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', - }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - tags: ['common'], - settings: { - controller: - "['$scope', function($scope) { $scope.$watch('submission.data', function(data) { console.log(data); }, true); }]", - }, - revisions: '', - _vid: 0, - controller: '', - properties: {}, -}; - -export const inlineEmbedFormPortal = { - _id: '617c032c68daf082ce063303', - type: 'form', - tags: [], - owner: '5e4aa9cf4037892ed27d5550', - components: [ - { - label: 'HTML', - tag: 'div', - attrs: [{ attr: '', value: '' }], - content: - "

Quick Inline Embed

\r\n

To quickly embed this form without using any framework, you can use the following code snippit and configure it using the Inline Embed Configuration form below.

\r\n

See our Inline Embed Documentation to know more about it.

", - refreshOnChange: false, - key: 'html1', - type: 'htmlelement', - input: false, - tableView: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'emraund', - }, - { - label: 'HTML', - tag: 'pre', - attrs: [{ attr: '', value: '' }], - content: - '', - refreshOnChange: true, - key: 'html', - type: 'htmlelement', - input: false, - tableView: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'e3wopjp', - }, - { - label: 'Copy to Clipboard', - action: 'custom', - showValidations: false, - theme: 'success', - block: true, - leftIcon: 'fa fa-copy', - tableView: false, - key: 'copyToClipboard', - type: 'button', - custom: 'var embedCode = document.getElementById(\'embed-code\');\nif (embedCode) {\n embedCode.focus();\n embedCode.select();\n document.execCommand("copy");\n}', - input: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - size: 'md', - rightIcon: '', - disableOnInvalid: false, - id: 'eq2y2ul', - }, - { - title: 'Inline Embed Configuration', - collapsible: false, - key: 'embedConfiguration', - type: 'panel', - label: 'Inline Embed Configuration', - input: false, - tableView: false, - components: [ - { - label: 'Embed Script', - customDefaultValue: "value = instance.options?.quickInlineEmbed || '';", - key: 'embed', - type: 'hidden', - tableView: true, - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + title: 'Advanced Settings', + collapsible: true, + key: 'advancedSettings', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ + { + label: 'Redirect', + tableView: true, + key: 'redirect', + type: 'url', + input: true, }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'eq04647', - }, - { - label: 'Project', - tableView: true, - key: 'project', - type: 'hidden', - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + { + label: 'Submission Endpoint', + tableView: true, + key: 'submit', + type: 'url', + input: true, }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'eowdp4', - }, - { - label: 'Base', - tableView: true, - key: 'base', - type: 'hidden', - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + { + label: 'Inherit Page CSS', + tableView: false, + defaultValue: true, + calculateValue: 'if (data.encapsulate) {\n value = true;\n}', + key: 'inherit', + type: 'checkbox', + input: true, }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - id: 'e2ayb69', - }, - { - label: 'Form Url', - customDefaultValue: "value = instance.options?.embedFormSrc || '';", - key: 'src', - type: 'hidden', - input: true, - tableView: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + { + label: 'Debug Mode', + tableView: false, + key: 'debug', + type: 'checkbox', + input: true, + defaultValue: false, }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - inputType: 'hidden', - id: 'ep1qgx', - }, - { - label: 'Template', - widget: 'choicesjs', - tableView: true, - data: { - values: [ - { label: 'Boostrap 4', value: 'false' }, - { label: 'USWDS', value: 'uswds' }, - ], - json: '', - url: '', - resource: '', - custom: '', + { + label: 'Custom Configurations', + editor: 'ace', + autoExpand: false, + tableView: true, + key: 'config', + type: 'textarea', + as: 'json', + input: true, }, - key: 'template', - type: 'select', - input: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - onlyAvailableItems: false, + { + input: true, + key: 'before', + tableView: true, + label: 'Before Render Handler', + type: 'textarea', + editor: 'ace', + as: 'string', }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - idPath: 'id', - clearOnRefresh: false, - limit: 100, - dataSrc: 'values', - valueProperty: '', - lazyLoad: true, - filter: '', - searchEnabled: true, - searchDebounce: 0.3, - searchField: '', - minSearch: 0, - readOnlyValue: false, - authenticate: false, - ignoreCache: false, - template: '{{ item.label }}', - selectFields: '', - selectThreshold: 0.3, - uniqueOptions: false, - fuseOptions: { include: 'score', threshold: 0.3 }, - indexeddb: { filter: {} }, - customOptions: {}, - useExactSearch: false, - id: 'ewk9iop', - }, - { - title: 'Advanced Settings', - collapsible: true, - key: 'advancedSettings', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Redirect', - tooltip: - 'The URL you would like to redirect to after the form is submitted. ', - tableView: true, - key: 'redirect', - type: 'url', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'url', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'et7ayx', - }, - { - label: 'Submission Endpoint', - tooltip: - 'The endpoint you would like to POST the submission toward. This allows you to send the submission to endpoints other than the default submission endpoint.', - tableView: true, - key: 'submit', - type: 'url', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'url', - inputFormat: 'plain', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - id: 'epa9s3i', - }, - { - label: 'Inherit Page CSS', - tooltip: - 'When it is unchecked, it loads all dependent CSS libraries to render the form.', - tableView: false, - defaultValue: false, - calculateValue: 'if (data.encapsulate) {\n value = true;\n}', - key: 'inherit', - type: 'checkbox', - input: true, - calculateValueMode: 'json', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - inputType: 'checkbox', - value: '', - name: '', - id: 'e23lxjq', - }, - { - label: 'Debug Mode', - tooltip: - 'Add a number of console.log records to the browser on how this form is progressing through the embedding code.', - tableView: false, - defaultValue: false, - key: 'debug', - type: 'checkbox', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: true, - labelPosition: 'right', - description: '', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - inputType: 'checkbox', - value: '', - name: '', - id: 'eh4hyc', - }, - { - label: 'Custom Configurations', - description: - 'The following FormioConfig parameters can be specified: config, form, submission, libs.\n

Example:\n { "config": { "readOnly": true } }.\n
Click here for more examples.\n

\n', - tooltip: - 'Add configuration in JSON format for the global FormioConfig variable to control the embedded flow', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'config', - type: 'textarea', - as: 'json', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - minWords: '', - maxWords: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'html', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - rows: 3, - wysiwyg: false, - fixedSize: true, - id: 'elmjv3ki', - }, - { - label: 'Before Render Handler', - description: - 'The callback accepts the following parameters: Formio, element, config. \n

Example:\nfunction(Formio, element, config) { console.log(Formio, element, config); }\n

', - tooltip: - 'Provide a callback that is executed before the Form is rendered.', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'before', - type: 'textarea', - as: 'string', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - minWords: '', - maxWords: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'html', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - rows: 3, - wysiwyg: false, - fixedSize: true, - id: 'ekd4ovh', - }, - { - label: 'After Render Handler', - description: - 'The callback accepts instance variable as a parameter.\n

Example: function(instance) { console.log(instance); }\n

', - tooltip: - 'Provide a callback that is called after the form is done rendering.', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'after', - type: 'textarea', - as: 'string', - input: true, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - errorLabel: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: { type: 'input' }, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: '', - maxLength: '', - pattern: '', - minWords: '', - maxWords: '', - }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - mask: false, - inputType: 'text', - inputFormat: 'html', - inputMask: '', - displayMask: '', - spellcheck: true, - truncateMultipleSpaces: false, - rows: 3, - wysiwyg: false, - fixedSize: true, - id: 'eiqb29', - }, - ], - collapsed: true, - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + { + label: 'After Render Handler', + editor: 'ace', + autoExpand: false, + tableView: true, + key: 'after', + type: 'textarea', + as: 'string', + input: true, }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - tree: false, - lazyLoad: false, - theme: 'default', - breadcrumb: 'default', - id: 'e71fwgr', + ], + collapsed: true, + hideOnChildrenHidden: false, }, - ], - hideOnChildrenHidden: false, - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: false, - refreshOn: '', - redrawOn: '', - modalEdit: false, - dataGridLabel: false, - labelPosition: 'top', - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - calculateServer: false, - widget: null, - attributes: {}, - validateOn: 'change', - validate: { - required: false, - custom: '', - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, + ], + hideOnChildrenHidden: false, }, - conditional: { show: null, when: null, eq: '' }, - overlay: { style: '', left: '', top: '', width: '', height: '' }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - addons: [], - tree: false, - lazyLoad: false, - theme: 'default', - breadcrumb: 'default', - id: 'e8be5t4', + ], + width: 6, + offset: 0, + push: 0, + pull: 0, + size: 'md', + currentWidth: 6, }, - ], - revisions: 'current', - _vid: 4, - title: 'Inline Embed Form - Portal', - display: 'form', - access: [ { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', - }, - ], - submissionAccess: [], - controller: '', - properties: {}, - settings: {}, - name: 'inlineEmbedFormPortal', - path: 'inlineembedformportal', - project: '5692b91fd1028f01000407e3', - created: '2021-10-29T14:20:28.581Z', - modified: '2022-11-17T15:09:31.641Z', - machineName: 'examples:inlineEmbedFormPortal', -}; - -export const validationRulesNyHealth = { - _id: '617051c6a8135f6a0780c364', - type: 'form', - tags: [], - owner: '5d921ec842af9789e5b81b26', - components: [ - { - title: 'Case 1', - collapsible: false, - key: 'case1', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 1:

\n

Box a value can not differ by a factor(.5) of n from Box b

\n• EX: 100(b) -> a(max)50', - refreshOnChange: false, - key: 'html1', - type: 'htmlelement', - input: false, - tableView: false, - }, - { - label: 'Box a', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - validate: { - customMessage: 'Needs to be within the range. ', - custom: 'valid = input >= (data.boxB * 0.5) && input <= (data.boxB * 1.5);', - }, - errorLabel: 'Box A Value', - key: 'boxA', - type: 'number', - input: true, - }, - { - label: 'Box b', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - key: 'boxB', - type: 'number', - input: true, - }, - ], - }, - { - title: 'Case 2 / Case 3', - collapsible: false, - key: 'case2', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ + components: [ + { + title: 'Embed Code', + collapsible: false, + key: 'embedCode', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 2:

\n

Box b must compare the value on the number of repeating section

\n• Value of b must match the amount of repeating section
\n• Number of repeating sections must not exceed value of b\n\n

Case 3:

\n

Box b in a repeating section 1a must be unique in all repeating section

', - refreshOnChange: false, - key: 'html', - type: 'htmlelement', - input: false, - tableView: false, + label: 'HTML', + tag: 'pre', + attrs: [{ attr: '', value: '' }], + content: + '', + refreshOnChange: true, + key: 'html', + type: 'htmlelement', + input: false, + tableView: false, }, { - label: 'Box b', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - calculateValue: - "var dataGrid = instance.root.getComponent('dataGrid');\ndataGrid.component.validate.minLength = parseInt(value, 10);\ndataGrid.component.validate.maxLength = parseInt(value, 10);\ninstance.root.redraw();", - key: 'boxB1', - type: 'number', - input: true, + label: 'Copy to Clipboard', + action: 'custom', + showValidations: false, + theme: 'success', + block: true, + leftIcon: 'fa fa-copy', + tableView: false, + key: 'copyToClipboard', + type: 'button', + custom: + 'var embedCode = document.getElementById(\'embed-code\');\nif (embedCode) {\n embedCode.focus();\n embedCode.select();\n document.execCommand("copy");\n}', + input: true, + hideOnChildrenHidden: false, }, - { - label: 'Data Grid', - reorder: false, - addAnotherPosition: 'bottom', - layoutFixed: false, - enableRowGroups: false, - initEmpty: false, - tableView: false, - defaultValue: [{ uniqueName: '' }], - key: 'dataGrid', - type: 'datagrid', - input: true, - components: [ - { - label: 'Unique Name', - tableView: true, - unique: true, - key: 'uniqueName', - type: 'textfield', - input: true, - }, - ], - }, - ], - breadcrumbClickable: true, - buttonSettings: { previous: true, cancel: true, next: true }, - scrollToTop: false, - }, - { - title: 'Case 4', - collapsible: false, - key: 'case7', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 4:

\n

Box b in a repeating section a1 must be greater then Box b in repeating section a2.

', - refreshOnChange: false, - key: 'html2', - type: 'htmlelement', - input: false, - tableView: false, - }, - { - title: 'Case 4.1', - collapsible: false, - key: 'case4', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Number1', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - key: 'number1', - type: 'number', - input: true, - }, - ], - }, - { - title: 'Case 4.2', - collapsible: false, - key: 'case42', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Number2', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - validate: { - customMessage: 'Value must be greater than or equal to Number1', - custom: 'valid = input>=data.number1;', - }, - key: 'number2', - type: 'number', - input: true, - }, - ], - }, - ], + ], + hideOnChildrenHidden: false, + }, + ], + width: 6, + offset: 0, + push: 0, + pull: 0, + size: 'md', + currentWidth: 6, }, + ], + hideOnChildrenHidden: false, + key: 'columns', + type: 'columns', + input: false, + tableView: false, + }, + ], + revisions: '', + _vid: 0, + title: 'Quick Inline Embed', + display: 'form', + access: [ + { + roles: ['5692b920d1028f01000407e4', '5692b920d1028f01000407e5', '5692b920d1028f01000407e6'], + type: 'read_all', + }, + ], + submissionAccess: [], + controller: '', + properties: {}, + settings: {}, + name: 'inlineembed', + path: 'embed', + project: '5692b91fd1028f01000407e3', + created: '2021-01-20T21:11:03.957Z', + modified: '2021-10-18T16:34:28.512Z', + machineName: 'examples:inlineEmbedConfiguration', +}; + +export const customerLoad = { + _id: '5aa316c59f3918304b469e82', + title: 'Customer Load', + display: 'form', + type: 'form', + components: [ + { + input: true, + tableView: true, + inputType: 'number', + label: 'Customer Number', + key: 'customerNumber', + validate: { required: true, min: 1, max: 9 }, + type: 'number', + }, + { input: true, tableView: true, label: 'Name', key: 'name', type: 'textfield' }, + { + input: true, + tableView: true, + label: 'Phone Number', + key: 'phoneNumber', + type: 'textfield', + }, + { input: true, label: 'Submit', tableView: false, key: 'submit', type: 'button' }, + ], + access: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { + roles: [ + '5692b920d1028f01000407e4', + '5692b920d1028f01000407e5', + '5692b920d1028f01000407e6', + '000000000000000000000000', + ], + type: 'read_all', + }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + submissionAccess: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { roles: [], type: 'read_all' }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + settings: {}, + name: 'customerLoad', + path: 'customerload', + owner: '55673dc04f0405dd28205bb7', + project: '5692b91fd1028f01000407e3', + tags: [], + created: '2018-03-09T23:20:37.966Z', + revisions: '', + _vid: 0, + modified: '2021-09-15T17:09:44.770Z', + machineName: 'examples:customerLoad', +}; + +export const kitchenSink = { + _id: '5d7a42f21cc1c2ca88ff2dd5', + type: 'form', + tags: [], + owner: '553dbfc08d22d5cb1a7024f2', + components: [ + { + label: 'Panel', + title: 'User Information', + collapsible: false, + mask: false, + tableView: false, + alwaysEnabled: false, + type: 'panel', + input: false, + key: 'panel2', + components: [ { - title: 'Case 5', - collapsible: false, - key: 'case5', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ + label: 'Columns', + columns: [ + { + components: [ { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 5:

\n

Box b in a repeating section a1 must be greater than Box c in repeating section a1. and also it can be applied to fields outside repeating section

\n', - refreshOnChange: false, - key: 'html3', - type: 'htmlelement', - input: false, - tableView: false, - }, - { - label: 'Data Grid', - reorder: false, - addAnotherPosition: 'bottom', - layoutFixed: false, - enableRowGroups: false, - initEmpty: false, - tableView: false, - defaultValue: [{}], - key: 'dataGrid1', - type: 'datagrid', - input: true, - components: [ - { - label: 'Number3', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - key: 'number3', - type: 'number', - input: true, - }, - { - label: 'Number4', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - validate: { - customMessage: 'must be greater than the value in Number3', - custom: 'valid = input>row.number3;\n', - }, - errorLabel: 'Number4', - key: 'number4', - type: 'number', - input: true, - }, - ], + label: 'First Name', + placeholder: 'Enter your first Name', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'firstName', + validate: { required: true }, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + hideOnChildrenHidden: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, + ], + width: 5, + offset: 0, + push: 0, + pull: 0, + type: 'column', + input: false, + hideOnChildrenHidden: false, + key: 'column', + tableView: true, + label: 'Column', + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + dataGridLabel: false, + labelPosition: 'top', + labelWidth: 30, + labelMargin: 3, + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + allowCalculateOverride: false, + widget: null, + refreshOn: '', + clearOnRefresh: false, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false }, + conditional: { show: null, when: null, eq: '' }, + id: 'eu6xaap', + size: 'md', + currentWidth: 5, + }, + { + components: [ { - title: 'Case 5 - Number outside of Section', - tooltip: - 'This is dependent on which value in the repeating section above would need to be validated against.', - collapsible: false, - key: 'case5NumberOutsideOfSection1', - type: 'panel', - label: 'Case 5 - Number outside of Section', - input: false, - tableView: false, - components: [ - { - label: 'Number5', - mask: false, - tableView: false, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - validate: { - customMessage: 'Value must be greater than Number3', - custom: 'valid = input>data.number3;', - }, - key: 'number6', - type: 'number', - input: true, - }, - ], - }, - ], - }, - { - title: 'Case 6 - Min / Max Date from Today', - collapsible: false, - key: 'case6', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'HTML', - attrs: [{ attr: '', value: '' }], - content: - '

Case 6:

\n

Date field d should have a date that is at most/least N days/weeks/months/years ago/ from today\n \n

', - refreshOnChange: false, - key: 'html4', - type: 'htmlelement', - input: false, - tableView: false, + label: 'Middle Name', + placeholder: 'Enter your middle name', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'middleName', + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + hideOnChildrenHidden: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, + ], + width: 2, + offset: 0, + push: 0, + pull: 0, + type: 'column', + input: false, + hideOnChildrenHidden: false, + key: 'column', + tableView: true, + label: 'Column', + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + dataGridLabel: false, + labelPosition: 'top', + labelWidth: 30, + labelMargin: 3, + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + allowCalculateOverride: false, + widget: null, + refreshOn: '', + clearOnRefresh: false, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false }, + conditional: { show: null, when: null, eq: '' }, + id: 'eorxgl', + size: 'md', + currentWidth: 2, + }, + { + width: 5, + offset: 0, + push: 0, + pull: 0, + type: 'column', + input: false, + hideOnChildrenHidden: false, + key: 'column', + tableView: true, + label: 'Column', + components: [ { - label: 'Date / Time', - tableView: false, - enableMinDateInput: true, - datePicker: { - disableWeekends: false, - disableWeekdays: false, - maxDate: "moment().add(10, 'days')", - minDate: "moment().subtract(10, 'days')", - }, - enableMaxDateInput: true, - key: 'dateTime', - type: 'datetime', - input: true, - widget: { - type: 'calendar', - displayInTimezone: 'viewer', - locale: 'en', - useLocaleSettings: false, - allowInput: true, - mode: 'single', - enableTime: true, - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - hourIncrement: 1, - minuteIncrement: 1, - time_24hr: false, - minDate: "moment().subtract(10, 'days')", - disableWeekends: false, - disableWeekdays: false, - maxDate: "moment().add(10, 'days')", - }, + label: 'Last Name', + placeholder: 'Enter your last name', + description: 'This is the name that should be on your birth certificate.', + tooltip: 'Seriously? You still need help with this one?', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'lastName', + validate: { required: true }, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + hideOnChildrenHidden: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, - ], - }, - { - type: 'button', - label: 'Submit', - key: 'submit', - disableOnInvalid: true, - input: true, - tableView: false, + ], + placeholder: '', + prefix: '', + customClass: '', + suffix: '', + multiple: false, + defaultValue: null, + protected: false, + unique: false, + persistent: true, + hidden: false, + clearOnHide: true, + dataGridLabel: false, + labelPosition: 'top', + labelWidth: 30, + labelMargin: 3, + description: '', + errorLabel: '', + tooltip: '', + hideLabel: false, + tabindex: '', + disabled: false, + autofocus: false, + dbIndex: false, + customDefaultValue: '', + calculateValue: '', + allowCalculateOverride: false, + widget: null, + refreshOn: '', + clearOnRefresh: false, + validateOn: 'change', + validate: { required: false, custom: '', customPrivate: false }, + conditional: { show: null, when: null, eq: '' }, + id: 'e02wdt8', + size: 'md', + currentWidth: 5, + }, + ], + mask: false, + tableView: false, + alwaysEnabled: false, + type: 'columns', + input: false, + key: 'columns', + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + hideOnChildrenHidden: false, }, - ], - revisions: '', - _vid: 0, - title: 'Validation Rules - NY Health', - display: 'wizard', - access: [ { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', + input: true, + tableView: true, + label: 'Email', + key: 'panel2Email', + type: 'email', + labelWidth: 30, + labelMargin: 3, + widget: { + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + clearOnRefresh: false, + alwaysEnabled: false, }, - ], - submissionAccess: [], - controller: '', - properties: {}, - settings: {}, - name: 'validationRulesNyHealth', - path: 'validationrulesnyhealth', - project: '5692b91fd1028f01000407e3', - created: '2021-10-20T17:28:38.165Z', - modified: '2021-10-20T18:08:13.287Z', - machineName: 'examples:validationRulesNyHealth', -}; - -export const inlineembed = { - _id: '60089c6795f584688609f83c', - type: 'form', - tags: [], - owner: '553dbfc08d22d5cb1a7024f2', - components: [ { - html: '

This is a form that enables the configuration of a Quick Inline Embed for a Form.io form.

For advanced documentation on how to use this embedding feature, please see our Quick Inline Embed Documentation.

', - label: 'Content', - refreshOnChange: false, - key: 'content', - type: 'content', - input: false, - tableView: false, + label: 'Website', + inputMasks: [{ label: '', mask: '' }], + alwaysEnabled: false, + tableView: true, + key: 'website', + type: 'url', + input: true, }, { - label: 'Columns', - columns: [ - { - components: [ - { - title: 'Embed Configuration', - collapsible: false, - key: 'embedConfiguration', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Embed Script', - defaultValue: 'https://cdn.form.io/formiojs/formio.embed.js', - key: 'embed', - type: 'hidden', - tableView: true, - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - }, - { - label: 'Project', - tableView: true, - key: 'project', - type: 'hidden', - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - }, - { - label: 'Base', - tableView: true, - key: 'base', - type: 'hidden', - input: true, - mask: false, - inputType: 'text', - inputFormat: 'plain', - spellcheck: true, - hideOnChildrenHidden: false, - }, - { - label: 'Form URL', - tableView: true, - validate: { required: true }, - key: 'src', - type: 'textfield', - input: true, - defaultValue: 'https://examples.form.io/example', - hideOnChildrenHidden: false, - }, - { - label: 'Template', - widget: 'choicesjs', - tableView: true, - data: { - values: [ - { label: 'Boostrap 4', value: 'false' }, - { label: 'USWDS', value: 'uswds' }, - ], - }, - key: 'template', - type: 'select', - input: true, - searchThreshold: 0.3, - hideOnChildrenHidden: false, - }, - { - title: 'Advanced Settings', - collapsible: true, - key: 'advancedSettings', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Redirect', - tableView: true, - key: 'redirect', - type: 'url', - input: true, - }, - { - label: 'Submission Endpoint', - tableView: true, - key: 'submit', - type: 'url', - input: true, - }, - { - label: 'Inherit Page CSS', - tableView: false, - defaultValue: true, - calculateValue: - 'if (data.encapsulate) {\n value = true;\n}', - key: 'inherit', - type: 'checkbox', - input: true, - }, - { - label: 'Debug Mode', - tableView: false, - key: 'debug', - type: 'checkbox', - input: true, - defaultValue: false, - }, - { - label: 'Custom Configurations', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'config', - type: 'textarea', - as: 'json', - input: true, - }, - { - input: true, - key: 'before', - tableView: true, - label: 'Before Render Handler', - type: 'textarea', - editor: 'ace', - as: 'string', - }, - { - label: 'After Render Handler', - editor: 'ace', - autoExpand: false, - tableView: true, - key: 'after', - type: 'textarea', - as: 'string', - input: true, - }, - ], - collapsed: true, - hideOnChildrenHidden: false, - }, - ], - hideOnChildrenHidden: false, - }, - ], - width: 6, - offset: 0, - push: 0, - pull: 0, - size: 'md', - currentWidth: 6, - }, - { - components: [ - { - title: 'Embed Code', - collapsible: false, - key: 'embedCode', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'HTML', - tag: 'pre', - attrs: [{ attr: '', value: '' }], - content: - '', - refreshOnChange: true, - key: 'html', - type: 'htmlelement', - input: false, - tableView: false, - }, - { - label: 'Copy to Clipboard', - action: 'custom', - showValidations: false, - theme: 'success', - block: true, - leftIcon: 'fa fa-copy', - tableView: false, - key: 'copyToClipboard', - type: 'button', - custom: 'var embedCode = document.getElementById(\'embed-code\');\nif (embedCode) {\n embedCode.focus();\n embedCode.select();\n document.execCommand("copy");\n}', - input: true, - hideOnChildrenHidden: false, - }, - ], - hideOnChildrenHidden: false, - }, - ], - width: 6, - offset: 0, - push: 0, - pull: 0, - size: 'md', - currentWidth: 6, - }, - ], - hideOnChildrenHidden: false, - key: 'columns', - type: 'columns', - input: false, - tableView: false, + key: 'panel2Panel', + input: false, + title: 'Other Information', + theme: 'primary', + tableView: false, + components: [ + { + input: true, + tableView: true, + label: 'Phone Number', + key: 'panel2PhoneNumber', + type: 'phoneNumber', + labelWidth: 30, + labelMargin: 3, + widget: { + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + clearOnRefresh: false, + alwaysEnabled: false, + }, + { + input: true, + tableView: false, + inputType: 'password', + label: 'Password', + key: 'panel2Password', + protected: true, + type: 'password', + labelWidth: 30, + labelMargin: 3, + widget: { + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + clearOnRefresh: false, + alwaysEnabled: false, + }, + { + label: 'SSN', + inputMask: '999 - 99 - 9999', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'ssn', + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + input: true, + tableView: true, + label: 'Birthday', + key: 'panel2Birthday', + datePicker: { datepickerMode: 'day' }, + type: 'datetime', + suffix: '\n', + widget: { + type: 'calendar', + displayInTimezone: 'viewer', + locale: 'en', + useLocaleSettings: false, + allowInput: true, + mode: 'single', + enableTime: true, + noCalendar: false, + format: 'yyyy-MM-dd hh:mm a', + hourIncrement: 1, + minuteIncrement: 1, + time_24hr: false, + minDate: null, + maxDate: null, + }, + defaultValue: null, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + alwaysEnabled: false, + }, + { + input: true, + tableView: true, + inputType: 'text', + label: 'Salary', + key: 'salary', + suffix: 'USD', + delimiter: true, + decimalLimit: 2, + requireDecimal: true, + type: 'currency', + tooltip: 'Enter your yearly salary', + description: 'Your yearly earnings before taxes.', + lockKey: true, + labelWidth: 30, + labelMargin: 3, + widget: null, + clearOnRefresh: false, + alwaysEnabled: false, + }, + { + input: true, + tableView: true, + inputType: 'number', + label: 'Number of Pets', + key: 'panel2NumberofPets', + prefix: '#', + type: 'number', + labelWidth: 30, + labelMargin: 3, + widget: null, + clearOnRefresh: false, + alwaysEnabled: false, + }, + { + input: true, + tableView: true, + label: 'Favorite Month', + key: 'panel2FavoriteMonth', + data: { + values: [ + { value: 'january', label: 'January' }, + { value: 'february', label: 'February' }, + { value: 'march', label: 'March' }, + { value: 'april', label: 'April' }, + { value: 'may', label: 'May' }, + { value: 'june', label: 'June' }, + { value: 'july', label: 'July' }, + { value: 'august', label: 'August' }, + { value: 'september', label: 'September' }, + { value: 'october', label: 'October' }, + { value: 'november', label: 'November' }, + { value: 'december', label: 'December' }, + ], + }, + valueProperty: 'value', + defaultValue: 'may', + type: 'select', + labelWidth: 30, + labelMargin: 3, + alwaysEnabled: false, + }, + { + input: true, + tableView: true, + label: 'Favorite Things', + key: 'panel2FavoriteThings', + data: { + values: [ + { value: 'raindropsOnRoses', label: 'Raindrops on roses' }, + { value: 'whiskersOnKittens', label: 'Whiskers on Kittens' }, + { + value: 'brightCopperKettles', + label: 'Bright Copper Kettles', + }, + { value: 'warmWoolenMittens', label: 'Warm Woolen Mittens' }, + ], + }, + valueProperty: 'value', + multiple: true, + type: 'select', + labelWidth: 30, + labelMargin: 3, + alwaysEnabled: false, + }, + { + input: true, + tableView: true, + label: 'Message', + key: 'panel2PanelMessage', + type: 'textarea', + inputFormat: 'plain', + }, + { + input: true, + tableView: true, + label: 'Favorite Color', + key: 'panel2FavoriteColor', + values: [ + { value: 'blue', label: 'Blue', shortcut: '' }, + { value: 'red', label: 'Red', shortcut: '' }, + { value: 'green', label: 'Green', shortcut: '' }, + { value: 'yellow', label: 'Yellow', shortcut: '' }, + { value: 'purple', label: 'Purple', shortcut: '' }, + { value: 'orange', label: 'Orange', shortcut: '' }, + ], + type: 'radio', + optionsLabelPosition: 'right', + tooltip: 'Select your favorite color.', + inline: true, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + alwaysEnabled: false, + }, + { + input: true, + tableView: true, + label: 'Favorite Fruits', + key: 'panel2FavoriteFruits', + values: [ + { value: 'apple', label: 'Apple', shortcut: '' }, + { value: 'orange', label: 'Orange', shortcut: '' }, + { value: 'banana', label: 'Banana', shortcut: '' }, + { value: 'peach', label: 'Peach', shortcut: '' }, + { value: 'strawberry', label: 'Strawberry', shortcut: '' }, + ], + type: 'selectboxes', + optionsLabelPosition: 'right', + inputType: 'checkbox', + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + alwaysEnabled: false, + }, + ], + type: 'panel', + collapsible: true, + collapsed: true, + label: 'Panel', }, - ], - revisions: '', - _vid: 0, - title: 'Quick Inline Embed', - display: 'form', - access: [ { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', + label: 'Bio', + editor: 'ckeditor', + tableView: true, + alwaysEnabled: false, + wysiwyg: { + theme: 'snow', + placeholder: '', + modules: { + clipboard: { matchVisual: false }, + toolbar: [ + [{ size: ['small', false, 'large', 'huge'] }], + [{ header: [1, 2, 3, 4, 5, 6, false] }], + [{ font: [] }], + [ + 'bold', + 'italic', + 'underline', + 'strike', + { script: 'sub' }, + { script: 'super' }, + 'clean', + ], + [{ color: [] }, { background: [] }], + [ + { list: 'ordered' }, + { list: 'bullet' }, + { indent: '-1' }, + { indent: '+1' }, + { align: [] }, + ], + ['blockquote', 'code-block'], + ['link', 'image', 'video', 'formula', 'source'], + ], + }, + rows: 10, + base64Upload: true, + image: { + toolbar: [ + 'imageTextAlternative', + '|', + 'imageStyle:alignLeft', + 'imageStyle:alignCenter', + 'imageStyle:full', + 'imageStyle:alignRight', + ], + styles: ['full', 'side', 'alignLeft', 'alignCenter', 'alignRight'], + }, + disableNativeSpellChecker: false, + mediaEmbed: { previewsInData: true }, + }, + rows: 10, + type: 'textarea', + input: true, + key: 'bio', + defaultValue: '


', + inputFormat: 'plain', + autoExpand: false, + isUploadEnabled: false, + reorder: false, + widget: { + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, - ], - submissionAccess: [], - controller: '', - properties: {}, - settings: {}, - name: 'inlineembed', - path: 'embed', - project: '5692b91fd1028f01000407e3', - created: '2021-01-20T21:11:03.957Z', - modified: '2021-10-18T16:34:28.512Z', - machineName: 'examples:inlineEmbedConfiguration', -}; - -export const customerLoad = { - _id: '5aa316c59f3918304b469e82', - title: 'Customer Load', - display: 'form', - type: 'form', - components: [ + ], + collapsed: false, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + path: 'panel2', + }, + { + label: 'Education', + reorder: false, + mask: false, + tableView: true, + alwaysEnabled: false, + type: 'editgrid', + input: true, + key: 'education', + components: [ { - input: true, - tableView: true, - inputType: 'number', - label: 'Customer Number', - key: 'customerNumber', - validate: { required: true, min: 1, max: 9 }, - type: 'number', + label: 'School', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'school', + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, - { input: true, tableView: true, label: 'Name', key: 'name', type: 'textfield' }, { - input: true, - tableView: true, - label: 'Phone Number', - key: 'phoneNumber', - type: 'textfield', + label: 'Degree', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'degree', + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, - { input: true, label: 'Submit', tableView: false, key: 'submit', type: 'button' }, - ], - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - '000000000000000000000000', - ], - type: 'read_all', + label: 'Graduation Date', + hideInputLabels: false, + inputsLabelPosition: 'top', + fields: { day: { hide: false }, month: { hide: false }, year: { hide: false } }, + useLocaleSettings: false, + mask: false, + tableView: true, + alwaysEnabled: false, + type: 'day', + input: true, + key: 'graduationDate', + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - submissionAccess: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - settings: {}, - name: 'customerLoad', - path: 'customerload', - owner: '55673dc04f0405dd28205bb7', - project: '5692b91fd1028f01000407e3', - tags: [], - created: '2018-03-09T23:20:37.966Z', - revisions: '', - _vid: 0, - modified: '2021-09-15T17:09:44.770Z', - machineName: 'examples:customerLoad', -}; - -export const kitchenSink = { - _id: '5d7a42f21cc1c2ca88ff2dd5', - type: 'form', - tags: [], - owner: '553dbfc08d22d5cb1a7024f2', - components: [ + ], + templates: { + header: + '
\n {%util.eachComponent(components, function(component) { %} \n
\n {{ component.label }} \n
\n {% }) %} \n
', + row: '
\n {% util.eachComponent(components, function(component) { %}\n
\n {{ getView(component, row[component.key]) }}\n
\n {% }) %}\n {% if (!instance.options.readOnly) { %}\n
\n
\n \n \n
\n
\n {% } %}\n
', + }, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + removeRow: '', + }, + { + label: 'Survey', + alwaysEnabled: false, + tableView: false, + questions: [ + { label: 'Food', value: 'food' }, + { label: 'Experience', value: 'experience' }, + { label: 'Restrooms', value: 'restrooms' }, + { label: 'Staff', value: 'staff' }, + ], + values: [ + { label: 'Very Good', value: 'veryGood' }, + { label: 'Good', value: 'good' }, + { label: 'Average', value: 'average' }, + { label: 'Bad', value: 'bad' }, + { label: 'Awful', value: 'awful' }, + ], + key: 'survey1', + type: 'survey', + input: true, + }, + { + label: 'Children', + alwaysEnabled: false, + tableView: false, + key: 'children', + type: 'well', + input: false, + components: [ { - label: 'Panel', - title: 'User Information', - collapsible: false, - mask: false, - tableView: false, - alwaysEnabled: false, - type: 'panel', - input: false, - key: 'panel2', - components: [ - { - label: 'Columns', - columns: [ - { - components: [ - { - label: 'First Name', - placeholder: 'Enter your first Name', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'firstName', - validate: { required: true }, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - hideOnChildrenHidden: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - width: 5, - offset: 0, - push: 0, - pull: 0, - type: 'column', - input: false, - hideOnChildrenHidden: false, - key: 'column', - tableView: true, - label: 'Column', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - dataGridLabel: false, - labelPosition: 'top', - labelWidth: 30, - labelMargin: 3, - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - allowCalculateOverride: false, - widget: null, - refreshOn: '', - clearOnRefresh: false, - validateOn: 'change', - validate: { required: false, custom: '', customPrivate: false }, - conditional: { show: null, when: null, eq: '' }, - id: 'eu6xaap', - size: 'md', - currentWidth: 5, - }, - { - components: [ - { - label: 'Middle Name', - placeholder: 'Enter your middle name', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'middleName', - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - hideOnChildrenHidden: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - width: 2, - offset: 0, - push: 0, - pull: 0, - type: 'column', - input: false, - hideOnChildrenHidden: false, - key: 'column', - tableView: true, - label: 'Column', - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - dataGridLabel: false, - labelPosition: 'top', - labelWidth: 30, - labelMargin: 3, - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - allowCalculateOverride: false, - widget: null, - refreshOn: '', - clearOnRefresh: false, - validateOn: 'change', - validate: { required: false, custom: '', customPrivate: false }, - conditional: { show: null, when: null, eq: '' }, - id: 'eorxgl', - size: 'md', - currentWidth: 2, - }, - { - width: 5, - offset: 0, - push: 0, - pull: 0, - type: 'column', - input: false, - hideOnChildrenHidden: false, - key: 'column', - tableView: true, - label: 'Column', - components: [ - { - label: 'Last Name', - placeholder: 'Enter your last name', - description: - 'This is the name that should be on your birth certificate.', - tooltip: 'Seriously? You still need help with this one?', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'lastName', - validate: { required: true }, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - hideOnChildrenHidden: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - placeholder: '', - prefix: '', - customClass: '', - suffix: '', - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - dataGridLabel: false, - labelPosition: 'top', - labelWidth: 30, - labelMargin: 3, - description: '', - errorLabel: '', - tooltip: '', - hideLabel: false, - tabindex: '', - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: '', - calculateValue: '', - allowCalculateOverride: false, - widget: null, - refreshOn: '', - clearOnRefresh: false, - validateOn: 'change', - validate: { required: false, custom: '', customPrivate: false }, - conditional: { show: null, when: null, eq: '' }, - id: 'e02wdt8', - size: 'md', - currentWidth: 5, - }, - ], - mask: false, - tableView: false, - alwaysEnabled: false, - type: 'columns', - input: false, - key: 'columns', - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - hideOnChildrenHidden: false, - }, - { - input: true, - tableView: true, - label: 'Email', - key: 'panel2Email', - type: 'email', - labelWidth: 30, - labelMargin: 3, - widget: { - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', + label: 'Children', + reorder: false, + addAnotherPosition: 'bottom', + defaultOpen: false, + layoutFixed: false, + enableRowGroups: false, + alwaysEnabled: false, + tableView: false, + key: 'children', + type: 'datagrid', + input: true, + components: [ + { + label: 'First Name', + widget: { + i18n: { + lng: 'en', + resources: { + en: { + translation: { + complete: 'Submission Complete', + error: 'Please fix the following errors before submitting.', + required: '{{field}} is required', + pattern: '{{field}} does not match the pattern {{pattern}}', + minLength: '{{field}} must be longer than {{length}} characters.', + maxLength: '{{field}} must be shorter than {{length}} characters.', + minWords: '{{field}} must have more than {{length}} words.', + maxWords: '{{field}} must have less than {{length}} words.', + min: '{{field}} cannot be less than {{min}}.', + max: '{{field}} cannot be greater than {{max}}.', + minSelectedCount: + 'You must select at least {{minCount}} items to continue.', + maxSelectedCount: + 'You can only select up to {{maxCount}} items to continue.', + maxDate: '{{field}} should not contain date after {{- maxDate}}', + minDate: '{{field}} should not contain date before {{- minDate}}', + invalid_email: '{{field}} must be a valid email.', + invalid_url: '{{field}} must be a valid url.', + invalid_regex: '{{field}} does not match the pattern {{regex}}.', + invalid_date: '{{field}} is not a valid date.', + invalid_day: '{{field}} is not a valid day.', + mask: '{{field}} does not match the mask.', + stripe: '{{stripe}}', + month: 'Month', + day: 'Day', + year: 'Year', + january: 'January', + february: 'February', + march: 'March', + april: 'April', + may: 'May', + june: 'June', + july: 'July', + august: 'August', + september: 'September', + october: 'October', + november: 'November', + december: 'December', + next: 'Next', + previous: 'Previous', + cancel: 'Cancel', + submit: 'Submit Form', + }, }, - clearOnRefresh: false, - alwaysEnabled: false, + }, }, - { - label: 'Website', - inputMasks: [{ label: '', mask: '' }], - alwaysEnabled: false, - tableView: true, - key: 'website', - type: 'url', - input: true, - }, - { - key: 'panel2Panel', - input: false, - title: 'Other Information', - theme: 'primary', - tableView: false, - components: [ - { - input: true, - tableView: true, - label: 'Phone Number', - key: 'panel2PhoneNumber', - type: 'phoneNumber', - labelWidth: 30, - labelMargin: 3, - widget: { - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: false, - inputType: 'password', - label: 'Password', - key: 'panel2Password', - protected: true, - type: 'password', - labelWidth: 30, - labelMargin: 3, - widget: { - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - label: 'SSN', - inputMask: '999 - 99 - 9999', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'ssn', - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - input: true, - tableView: true, - label: 'Birthday', - key: 'panel2Birthday', - datePicker: { datepickerMode: 'day' }, - type: 'datetime', - suffix: '\n', - widget: { - type: 'calendar', - displayInTimezone: 'viewer', - locale: 'en', - useLocaleSettings: false, - allowInput: true, - mode: 'single', - enableTime: true, - noCalendar: false, - format: 'yyyy-MM-dd hh:mm a', - hourIncrement: 1, - minuteIncrement: 1, - time_24hr: false, - minDate: null, - maxDate: null, - }, - defaultValue: null, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - inputType: 'text', - label: 'Salary', - key: 'salary', - suffix: 'USD', - delimiter: true, - decimalLimit: 2, - requireDecimal: true, - type: 'currency', - tooltip: 'Enter your yearly salary', - description: 'Your yearly earnings before taxes.', - lockKey: true, - labelWidth: 30, - labelMargin: 3, - widget: null, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - inputType: 'number', - label: 'Number of Pets', - key: 'panel2NumberofPets', - prefix: '#', - type: 'number', - labelWidth: 30, - labelMargin: 3, - widget: null, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Favorite Month', - key: 'panel2FavoriteMonth', - data: { - values: [ - { value: 'january', label: 'January' }, - { value: 'february', label: 'February' }, - { value: 'march', label: 'March' }, - { value: 'april', label: 'April' }, - { value: 'may', label: 'May' }, - { value: 'june', label: 'June' }, - { value: 'july', label: 'July' }, - { value: 'august', label: 'August' }, - { value: 'september', label: 'September' }, - { value: 'october', label: 'October' }, - { value: 'november', label: 'November' }, - { value: 'december', label: 'December' }, - ], - }, - valueProperty: 'value', - defaultValue: 'may', - type: 'select', - labelWidth: 30, - labelMargin: 3, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Favorite Things', - key: 'panel2FavoriteThings', - data: { - values: [ - { value: 'raindropsOnRoses', label: 'Raindrops on roses' }, - { value: 'whiskersOnKittens', label: 'Whiskers on Kittens' }, - { - value: 'brightCopperKettles', - label: 'Bright Copper Kettles', - }, - { value: 'warmWoolenMittens', label: 'Warm Woolen Mittens' }, - ], - }, - valueProperty: 'value', - multiple: true, - type: 'select', - labelWidth: 30, - labelMargin: 3, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Message', - key: 'panel2PanelMessage', - type: 'textarea', - inputFormat: 'plain', - }, - { - input: true, - tableView: true, - label: 'Favorite Color', - key: 'panel2FavoriteColor', - values: [ - { value: 'blue', label: 'Blue', shortcut: '' }, - { value: 'red', label: 'Red', shortcut: '' }, - { value: 'green', label: 'Green', shortcut: '' }, - { value: 'yellow', label: 'Yellow', shortcut: '' }, - { value: 'purple', label: 'Purple', shortcut: '' }, - { value: 'orange', label: 'Orange', shortcut: '' }, - ], - type: 'radio', - optionsLabelPosition: 'right', - tooltip: 'Select your favorite color.', - inline: true, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Favorite Fruits', - key: 'panel2FavoriteFruits', - values: [ - { value: 'apple', label: 'Apple', shortcut: '' }, - { value: 'orange', label: 'Orange', shortcut: '' }, - { value: 'banana', label: 'Banana', shortcut: '' }, - { value: 'peach', label: 'Peach', shortcut: '' }, - { value: 'strawberry', label: 'Strawberry', shortcut: '' }, - ], - type: 'selectboxes', - optionsLabelPosition: 'right', - inputType: 'checkbox', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - ], - type: 'panel', - collapsible: true, - collapsed: true, - label: 'Panel', - }, - { - label: 'Bio', - editor: 'ckeditor', - tableView: true, - alwaysEnabled: false, - wysiwyg: { - theme: 'snow', - placeholder: '', - modules: { - clipboard: { matchVisual: false }, - toolbar: [ - [{ size: ['small', false, 'large', 'huge'] }], - [{ header: [1, 2, 3, 4, 5, 6, false] }], - [{ font: [] }], - [ - 'bold', - 'italic', - 'underline', - 'strike', - { script: 'sub' }, - { script: 'super' }, - 'clean', - ], - [{ color: [] }, { background: [] }], - [ - { list: 'ordered' }, - { list: 'bullet' }, - { indent: '-1' }, - { indent: '+1' }, - { align: [] }, - ], - ['blockquote', 'code-block'], - ['link', 'image', 'video', 'formula', 'source'], - ], - }, - rows: 10, - base64Upload: true, - image: { - toolbar: [ - 'imageTextAlternative', - '|', - 'imageStyle:alignLeft', - 'imageStyle:alignCenter', - 'imageStyle:full', - 'imageStyle:alignRight', - ], - styles: ['full', 'side', 'alignLeft', 'alignCenter', 'alignRight'], - }, - disableNativeSpellChecker: false, - mediaEmbed: { previewsInData: true }, - }, - rows: 10, - type: 'textarea', - input: true, - key: 'bio', - defaultValue: '


', - inputFormat: 'plain', - autoExpand: false, - isUploadEnabled: false, - reorder: false, - widget: { - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', + language: 'en', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + alwaysEnabled: false, + tableView: true, + key: 'firstName', + type: 'textfield', + input: true, + inDataGrid: true, + row: '0-0', + }, + { + label: 'Last Name', + widget: { + i18n: { + lng: 'en', + resources: { + en: { + translation: { + complete: 'Submission Complete', + error: 'Please fix the following errors before submitting.', + required: '{{field}} is required', + pattern: '{{field}} does not match the pattern {{pattern}}', + minLength: '{{field}} must be longer than {{length}} characters.', + maxLength: '{{field}} must be shorter than {{length}} characters.', + minWords: '{{field}} must have more than {{length}} words.', + maxWords: '{{field}} must have less than {{length}} words.', + min: '{{field}} cannot be less than {{min}}.', + max: '{{field}} cannot be greater than {{max}}.', + minSelectedCount: + 'You must select at least {{minCount}} items to continue.', + maxSelectedCount: + 'You can only select up to {{maxCount}} items to continue.', + maxDate: '{{field}} should not contain date after {{- maxDate}}', + minDate: '{{field}} should not contain date before {{- minDate}}', + invalid_email: '{{field}} must be a valid email.', + invalid_url: '{{field}} must be a valid url.', + invalid_regex: '{{field}} does not match the pattern {{regex}}.', + invalid_date: '{{field}} is not a valid date.', + invalid_day: '{{field}} is not a valid day.', + mask: '{{field}} does not match the mask.', + stripe: '{{stripe}}', + month: 'Month', + day: 'Day', + year: 'Year', + january: 'January', + february: 'February', + march: 'March', + april: 'April', + may: 'May', + june: 'June', + july: 'July', + august: 'August', + september: 'September', + october: 'October', + november: 'November', + december: 'December', + next: 'Next', + previous: 'Previous', + cancel: 'Cancel', + submit: 'Submit Form', + }, }, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, + }, }, - ], - collapsed: false, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - path: 'panel2', + language: 'en', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + alwaysEnabled: false, + tableView: true, + key: 'lastName', + type: 'textfield', + input: true, + inDataGrid: true, + row: '0-1', + }, + ], + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, + ], + path: 'children', + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + title: 'Guardian Information', + collapsible: false, + alwaysEnabled: false, + tableView: false, + key: 'guardianInformation', + type: 'panel', + input: false, + label: 'Panel', + components: [ { - label: 'Education', - reorder: false, - mask: false, - tableView: true, - alwaysEnabled: false, - type: 'editgrid', - input: true, - key: 'education', - components: [ - { - label: 'School', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'school', - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', + label: 'Guardian', + alwaysEnabled: false, + tableView: false, + key: 'guardian', + type: 'container', + input: true, + components: [ + { + label: 'First Name', + widget: { + i18n: { + lng: 'en', + resources: { + en: { + translation: { + complete: 'Submission Complete', + error: 'Please fix the following errors before submitting.', + required: '{{field}} is required', + pattern: '{{field}} does not match the pattern {{pattern}}', + minLength: '{{field}} must be longer than {{length}} characters.', + maxLength: '{{field}} must be shorter than {{length}} characters.', + minWords: '{{field}} must have more than {{length}} words.', + maxWords: '{{field}} must have less than {{length}} words.', + min: '{{field}} cannot be less than {{min}}.', + max: '{{field}} cannot be greater than {{max}}.', + minSelectedCount: + 'You must select at least {{minCount}} items to continue.', + maxSelectedCount: + 'You can only select up to {{maxCount}} items to continue.', + maxDate: '{{field}} should not contain date after {{- maxDate}}', + minDate: '{{field}} should not contain date before {{- minDate}}', + invalid_email: '{{field}} must be a valid email.', + invalid_url: '{{field}} must be a valid url.', + invalid_regex: '{{field}} does not match the pattern {{regex}}.', + invalid_date: '{{field}} is not a valid date.', + invalid_day: '{{field}} is not a valid day.', + mask: '{{field}} does not match the mask.', + stripe: '{{stripe}}', + month: 'Month', + day: 'Day', + year: 'Year', + january: 'January', + february: 'February', + march: 'March', + april: 'April', + may: 'May', + june: 'June', + july: 'July', + august: 'August', + september: 'September', + october: 'October', + november: 'November', + december: 'December', + next: 'Next', + previous: 'Previous', + cancel: 'Cancel', + submit: 'Submit Form', + }, }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, + }, }, - { - label: 'Degree', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'degree', - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', + language: 'en', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + alwaysEnabled: false, + tableView: true, + key: 'firstName1', + type: 'textfield', + input: true, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + label: 'Last Name', + widget: { + i18n: { + lng: 'en', + resources: { + en: { + translation: { + complete: 'Submission Complete', + error: 'Please fix the following errors before submitting.', + required: '{{field}} is required', + pattern: '{{field}} does not match the pattern {{pattern}}', + minLength: '{{field}} must be longer than {{length}} characters.', + maxLength: '{{field}} must be shorter than {{length}} characters.', + minWords: '{{field}} must have more than {{length}} words.', + maxWords: '{{field}} must have less than {{length}} words.', + min: '{{field}} cannot be less than {{min}}.', + max: '{{field}} cannot be greater than {{max}}.', + minSelectedCount: + 'You must select at least {{minCount}} items to continue.', + maxSelectedCount: + 'You can only select up to {{maxCount}} items to continue.', + maxDate: '{{field}} should not contain date after {{- maxDate}}', + minDate: '{{field}} should not contain date before {{- minDate}}', + invalid_email: '{{field}} must be a valid email.', + invalid_url: '{{field}} must be a valid url.', + invalid_regex: '{{field}} does not match the pattern {{regex}}.', + invalid_date: '{{field}} is not a valid date.', + invalid_day: '{{field}} is not a valid day.', + mask: '{{field}} does not match the mask.', + stripe: '{{stripe}}', + month: 'Month', + day: 'Day', + year: 'Year', + january: 'January', + february: 'February', + march: 'March', + april: 'April', + may: 'May', + june: 'June', + july: 'July', + august: 'August', + september: 'September', + october: 'October', + november: 'November', + december: 'December', + next: 'Next', + previous: 'Previous', + cancel: 'Cancel', + submit: 'Submit Form', + }, }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Graduation Date', - hideInputLabels: false, - inputsLabelPosition: 'top', - fields: { day: { hide: false }, month: { hide: false }, year: { hide: false } }, - useLocaleSettings: false, - mask: false, - tableView: true, - alwaysEnabled: false, - type: 'day', - input: true, - key: 'graduationDate', - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, + }, }, - ], - templates: { - header: '
\n {%util.eachComponent(components, function(component) { %} \n
\n {{ component.label }} \n
\n {% }) %} \n
', - row: '
\n {% util.eachComponent(components, function(component) { %}\n
\n {{ getView(component, row[component.key]) }}\n
\n {% }) %}\n {% if (!instance.options.readOnly) { %}\n
\n
\n \n \n
\n
\n {% } %}\n
', + language: 'en', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + alwaysEnabled: false, + tableView: true, + key: 'lastName1', + type: 'textfield', + input: true, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - removeRow: '', - }, - { - label: 'Survey', - alwaysEnabled: false, - tableView: false, - questions: [ - { label: 'Food', value: 'food' }, - { label: 'Experience', value: 'experience' }, - { label: 'Restrooms', value: 'restrooms' }, - { label: 'Staff', value: 'staff' }, - ], - values: [ - { label: 'Very Good', value: 'veryGood' }, - { label: 'Good', value: 'good' }, - { label: 'Average', value: 'average' }, - { label: 'Bad', value: 'bad' }, - { label: 'Awful', value: 'awful' }, - ], - key: 'survey1', - type: 'survey', - input: true, + ], + path: 'guardian', + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, }, + ], + path: 'guardianInformation', + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + label: 'Tabs', + components: [ { - label: 'Children', - alwaysEnabled: false, - tableView: false, - key: 'children', - type: 'well', - input: false, - components: [ - { - label: 'Children', - reorder: false, - addAnotherPosition: 'bottom', - defaultOpen: false, - layoutFixed: false, - enableRowGroups: false, - alwaysEnabled: false, - tableView: false, - key: 'children', - type: 'datagrid', - input: true, - components: [ - { - label: 'First Name', - widget: { - i18n: { - lng: 'en', - resources: { - en: { - translation: { - complete: 'Submission Complete', - error: 'Please fix the following errors before submitting.', - required: '{{field}} is required', - pattern: - '{{field}} does not match the pattern {{pattern}}', - minLength: - '{{field}} must be longer than {{length}} characters.', - maxLength: - '{{field}} must be shorter than {{length}} characters.', - minWords: - '{{field}} must have more than {{length}} words.', - maxWords: - '{{field}} must have less than {{length}} words.', - min: '{{field}} cannot be less than {{min}}.', - max: '{{field}} cannot be greater than {{max}}.', - minSelectedCount: - 'You must select at least {{minCount}} items to continue.', - maxSelectedCount: - 'You can only select up to {{maxCount}} items to continue.', - maxDate: - '{{field}} should not contain date after {{- maxDate}}', - minDate: - '{{field}} should not contain date before {{- minDate}}', - invalid_email: '{{field}} must be a valid email.', - invalid_url: '{{field}} must be a valid url.', - invalid_regex: - '{{field}} does not match the pattern {{regex}}.', - invalid_date: '{{field}} is not a valid date.', - invalid_day: '{{field}} is not a valid day.', - mask: '{{field}} does not match the mask.', - stripe: '{{stripe}}', - month: 'Month', - day: 'Day', - year: 'Year', - january: 'January', - february: 'February', - march: 'March', - april: 'April', - may: 'May', - june: 'June', - july: 'July', - august: 'August', - september: 'September', - october: 'October', - november: 'November', - december: 'December', - next: 'Next', - previous: 'Previous', - cancel: 'Cancel', - submit: 'Submit Form', - }, - }, - }, - }, - language: 'en', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - alwaysEnabled: false, - tableView: true, - key: 'firstName', - type: 'textfield', - input: true, - inDataGrid: true, - row: '0-0', - }, - { - label: 'Last Name', - widget: { - i18n: { - lng: 'en', - resources: { - en: { - translation: { - complete: 'Submission Complete', - error: 'Please fix the following errors before submitting.', - required: '{{field}} is required', - pattern: - '{{field}} does not match the pattern {{pattern}}', - minLength: - '{{field}} must be longer than {{length}} characters.', - maxLength: - '{{field}} must be shorter than {{length}} characters.', - minWords: - '{{field}} must have more than {{length}} words.', - maxWords: - '{{field}} must have less than {{length}} words.', - min: '{{field}} cannot be less than {{min}}.', - max: '{{field}} cannot be greater than {{max}}.', - minSelectedCount: - 'You must select at least {{minCount}} items to continue.', - maxSelectedCount: - 'You can only select up to {{maxCount}} items to continue.', - maxDate: - '{{field}} should not contain date after {{- maxDate}}', - minDate: - '{{field}} should not contain date before {{- minDate}}', - invalid_email: '{{field}} must be a valid email.', - invalid_url: '{{field}} must be a valid url.', - invalid_regex: - '{{field}} does not match the pattern {{regex}}.', - invalid_date: '{{field}} is not a valid date.', - invalid_day: '{{field}} is not a valid day.', - mask: '{{field}} does not match the mask.', - stripe: '{{stripe}}', - month: 'Month', - day: 'Day', - year: 'Year', - january: 'January', - february: 'February', - march: 'March', - april: 'April', - may: 'May', - june: 'June', - july: 'July', - august: 'August', - september: 'September', - october: 'October', - november: 'November', - december: 'December', - next: 'Next', - previous: 'Previous', - cancel: 'Cancel', - submit: 'Submit Form', - }, - }, - }, - }, - language: 'en', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - alwaysEnabled: false, - tableView: true, - key: 'lastName', - type: 'textfield', - input: true, - inDataGrid: true, - row: '0-1', - }, - ], - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - path: 'children', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, + label: 'Tab 1', + key: 'tab1', + components: [ + { + label: 'One', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'one', + tab: 0, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + label: 'Two', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'two', + tab: 0, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + label: 'Tags', + alwaysEnabled: false, + tableView: false, + key: 'tags1', + type: 'tags', + input: true, + }, + ], }, { - title: 'Guardian Information', - collapsible: false, - alwaysEnabled: false, - tableView: false, - key: 'guardianInformation', - type: 'panel', - input: false, - label: 'Panel', - components: [ - { - label: 'Guardian', - alwaysEnabled: false, - tableView: false, - key: 'guardian', - type: 'container', - input: true, - components: [ - { - label: 'First Name', - widget: { - i18n: { - lng: 'en', - resources: { - en: { - translation: { - complete: 'Submission Complete', - error: 'Please fix the following errors before submitting.', - required: '{{field}} is required', - pattern: - '{{field}} does not match the pattern {{pattern}}', - minLength: - '{{field}} must be longer than {{length}} characters.', - maxLength: - '{{field}} must be shorter than {{length}} characters.', - minWords: - '{{field}} must have more than {{length}} words.', - maxWords: - '{{field}} must have less than {{length}} words.', - min: '{{field}} cannot be less than {{min}}.', - max: '{{field}} cannot be greater than {{max}}.', - minSelectedCount: - 'You must select at least {{minCount}} items to continue.', - maxSelectedCount: - 'You can only select up to {{maxCount}} items to continue.', - maxDate: - '{{field}} should not contain date after {{- maxDate}}', - minDate: - '{{field}} should not contain date before {{- minDate}}', - invalid_email: '{{field}} must be a valid email.', - invalid_url: '{{field}} must be a valid url.', - invalid_regex: - '{{field}} does not match the pattern {{regex}}.', - invalid_date: '{{field}} is not a valid date.', - invalid_day: '{{field}} is not a valid day.', - mask: '{{field}} does not match the mask.', - stripe: '{{stripe}}', - month: 'Month', - day: 'Day', - year: 'Year', - january: 'January', - february: 'February', - march: 'March', - april: 'April', - may: 'May', - june: 'June', - july: 'July', - august: 'August', - september: 'September', - october: 'October', - november: 'November', - december: 'December', - next: 'Next', - previous: 'Previous', - cancel: 'Cancel', - submit: 'Submit Form', - }, - }, - }, - }, - language: 'en', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - alwaysEnabled: false, - tableView: true, - key: 'firstName1', - type: 'textfield', - input: true, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Last Name', - widget: { - i18n: { - lng: 'en', - resources: { - en: { - translation: { - complete: 'Submission Complete', - error: 'Please fix the following errors before submitting.', - required: '{{field}} is required', - pattern: - '{{field}} does not match the pattern {{pattern}}', - minLength: - '{{field}} must be longer than {{length}} characters.', - maxLength: - '{{field}} must be shorter than {{length}} characters.', - minWords: - '{{field}} must have more than {{length}} words.', - maxWords: - '{{field}} must have less than {{length}} words.', - min: '{{field}} cannot be less than {{min}}.', - max: '{{field}} cannot be greater than {{max}}.', - minSelectedCount: - 'You must select at least {{minCount}} items to continue.', - maxSelectedCount: - 'You can only select up to {{maxCount}} items to continue.', - maxDate: - '{{field}} should not contain date after {{- maxDate}}', - minDate: - '{{field}} should not contain date before {{- minDate}}', - invalid_email: '{{field}} must be a valid email.', - invalid_url: '{{field}} must be a valid url.', - invalid_regex: - '{{field}} does not match the pattern {{regex}}.', - invalid_date: '{{field}} is not a valid date.', - invalid_day: '{{field}} is not a valid day.', - mask: '{{field}} does not match the mask.', - stripe: '{{stripe}}', - month: 'Month', - day: 'Day', - year: 'Year', - january: 'January', - february: 'February', - march: 'March', - april: 'April', - may: 'May', - june: 'June', - july: 'July', - august: 'August', - september: 'September', - october: 'October', - november: 'November', - december: 'December', - next: 'Next', - previous: 'Previous', - cancel: 'Cancel', - submit: 'Submit Form', - }, - }, - }, - }, - language: 'en', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - alwaysEnabled: false, - tableView: true, - key: 'lastName1', - type: 'textfield', - input: true, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - path: 'guardian', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - path: 'guardianInformation', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, + label: 'Tab 2', + key: 'tab2', + components: [ + { + label: 'Three', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'three', + tab: 1, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + label: 'Four', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'four', + tab: 1, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + ], }, { - label: 'Tabs', - components: [ - { - label: 'Tab 1', - key: 'tab1', - components: [ - { - label: 'One', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'one', - tab: 0, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Two', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'two', - tab: 0, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Tags', - alwaysEnabled: false, - tableView: false, - key: 'tags1', - type: 'tags', - input: true, - }, - ], - }, - { - label: 'Tab 2', - key: 'tab2', - components: [ - { - label: 'Three', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'three', - tab: 1, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Four', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'four', - tab: 1, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - }, - { - label: 'Tab 3', - key: 'tab3', - components: [ - { - label: 'Five', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'five', - tab: 2, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - { - label: 'Six', - tableView: true, - alwaysEnabled: false, - type: 'textfield', - input: true, - key: 'six', - tab: 2, - widget: { - type: '', - format: 'yyyy-MM-dd hh:mm a', - dateFormat: 'yyyy-MM-dd hh:mm a', - saveAs: 'text', - }, - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - }, - ], - }, - ], - mask: false, - tableView: true, - alwaysEnabled: false, - type: 'tabs', - input: false, - key: 'tabs2', - reorder: false, - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - path: 'tabs2', + label: 'Tab 3', + key: 'tab3', + components: [ + { + label: 'Five', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'five', + tab: 2, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + { + label: 'Six', + tableView: true, + alwaysEnabled: false, + type: 'textfield', + input: true, + key: 'six', + tab: 2, + widget: { + type: '', + format: 'yyyy-MM-dd hh:mm a', + dateFormat: 'yyyy-MM-dd hh:mm a', + saveAs: 'text', + }, + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + }, + ], }, + ], + mask: false, + tableView: true, + alwaysEnabled: false, + type: 'tabs', + input: false, + key: 'tabs2', + reorder: false, + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + path: 'tabs2', + }, + { + clearOnHide: false, + key: 'fieldset', + input: false, + tableView: false, + legend: 'Signature', + components: [ { - clearOnHide: false, - key: 'fieldset', - input: false, - tableView: false, - legend: 'Signature', - components: [ - { - key: 'fieldsetContent', - input: false, - html: '

This is some content

\n\n

Click the following if you agree to the rules.

\n\n
    \n\t
  • This
  • \n\t
  • is
  • \n\t
  • an
  • \n\t
  • important
  • \n\t
  • list
  • \n
\n', - type: 'content', - tableView: true, - label: 'Content', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'I agree to the rules', - dataGridLabel: false, - key: 'fieldsetIagreetotherules', - defaultValue: false, - type: 'checkbox', - tooltip: 'Check this if you agree.', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, - }, - { - input: true, - tableView: true, - label: 'Signature', - key: 'fieldsetSignature', - type: 'signature', - hideLabel: true, - labelWidth: 30, - labelMargin: 3, - widget: null, - clearOnRefresh: false, - alwaysEnabled: false, - }, - ], - type: 'fieldset', - hideLabel: true, - label: 'Field Set', - labelWidth: 30, - labelMargin: 3, - clearOnRefresh: false, - alwaysEnabled: false, + key: 'fieldsetContent', + input: false, + html: '

This is some content

\n\n

Click the following if you agree to the rules.

\n\n
    \n\t
  • This
  • \n\t
  • is
  • \n\t
  • an
  • \n\t
  • important
  • \n\t
  • list
  • \n
\n', + type: 'content', + tableView: true, + label: 'Content', + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + alwaysEnabled: false, }, { - type: 'button', - label: 'Submit', - key: 'submit', - disableOnInvalid: true, - input: true, - tableView: true, - alwaysEnabled: false, - labelWidth: 30, - labelMargin: 3, - widget: null, - clearOnRefresh: false, + input: true, + tableView: true, + label: 'I agree to the rules', + dataGridLabel: false, + key: 'fieldsetIagreetotherules', + defaultValue: false, + type: 'checkbox', + tooltip: 'Check this if you agree.', + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + alwaysEnabled: false, }, - ], - revisions: '', - _vid: 0, - title: 'Kitchen Sink', - display: 'form', - access: [ - { roles: [], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', + input: true, + tableView: true, + label: 'Signature', + key: 'fieldsetSignature', + type: 'signature', + hideLabel: true, + labelWidth: 30, + labelMargin: 3, + widget: null, + clearOnRefresh: false, + alwaysEnabled: false, }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - submissionAccess: [ - { roles: ['5692b920d1028f01000407e6'], type: 'create_own' }, - { roles: [], type: 'create_all' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'read_all' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - settings: {}, - properties: {}, - name: 'kitchenSink', - path: 'kitchensink', - project: '5692b91fd1028f01000407e3', - created: '2019-09-12T13:06:58.622Z', - modified: '2021-06-16T15:03:39.596Z', - machineName: 'examples:kitchenSink', + ], + type: 'fieldset', + hideLabel: true, + label: 'Field Set', + labelWidth: 30, + labelMargin: 3, + clearOnRefresh: false, + alwaysEnabled: false, + }, + { + type: 'button', + label: 'Submit', + key: 'submit', + disableOnInvalid: true, + input: true, + tableView: true, + alwaysEnabled: false, + labelWidth: 30, + labelMargin: 3, + widget: null, + clearOnRefresh: false, + }, + ], + revisions: '', + _vid: 0, + title: 'Kitchen Sink', + display: 'form', + access: [ + { roles: [], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { + roles: ['5692b920d1028f01000407e4', '5692b920d1028f01000407e5', '5692b920d1028f01000407e6'], + type: 'read_all', + }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + submissionAccess: [ + { roles: ['5692b920d1028f01000407e6'], type: 'create_own' }, + { roles: [], type: 'create_all' }, + { roles: [], type: 'read_own' }, + { roles: [], type: 'read_all' }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + settings: {}, + properties: {}, + name: 'kitchenSink', + path: 'kitchensink', + project: '5692b91fd1028f01000407e3', + created: '2019-09-12T13:06:58.622Z', + modified: '2021-06-16T15:03:39.596Z', + machineName: 'examples:kitchenSink', }; export const otherForm = { - _id: '59121aaaed27e70083924f5b', - machineName: 'examples:e', - modified: '2021-06-08T21:04:52.339Z', - title: 'E', - display: 'form', - name: 'e', - path: 'e', - project: '5692b91fd1028f01000407e3', - created: '2017-05-09T19:38:18.503Z', - components: [ - { - key: 'content', - input: false, - html: '

You are on Page E!

\n', - type: 'content', - tableView: false, - label: 'Content', - }, - { - label: 'Total', - mask: false, - spellcheck: true, - disabled: true, - tableView: true, - delimiter: false, - requireDecimal: false, - inputFormat: 'plain', - customDefaultValue: 'value = instance.root.data.score;', - calculateValue: { '+': [{ var: 'data.totalScore' }, { var: 'data.score' }] }, - key: 'total', - type: 'number', - inputType: 'number', - input: true, - }, - { - disabled: true, - type: 'number', - key: 'score', - label: 'Score', - inputType: 'number', - tableView: true, - input: true, - calculateValue: { - if: [ - { '==': [{ var: 'data.points' }, 'plus1'] }, - 1, - { '==': [{ var: 'data.points' }, 'plus2'] }, - 2, - { '==': [{ var: 'data.points' }, 'plus3'] }, - 3, - 0, - ], - }, - }, - { - input: true, - tableView: true, - label: 'Points', - key: 'points', - values: [ - { value: 'plus1', label: '+ 1' }, - { value: 'plus2', label: '+ 2' }, - { value: 'plus3', label: '+ 3' }, - { value: 'noChange', label: 'No Change' }, - ], - type: 'radio', - }, - { - input: true, - tableView: true, - label: 'Which page would you like to go to next?', - key: 'nextPage', - data: { - values: [ - { value: 'pageA', label: 'A' }, - { value: 'pageB', label: 'B' }, - { value: 'pageC', label: 'C' }, - { value: 'pageD', label: 'D' }, - { value: 'pageE', label: 'E' }, - { label: "I'm Done", value: 'done' }, - ], - }, - type: 'select', - lockKey: true, - }, - { input: true, label: 'Submit', tableView: false, key: 'submit', type: 'button' }, - ], - owner: '553dbfc08d22d5cb1a7024f2', - submissionAccess: [ - { roles: ['5692b920d1028f01000407e6'], type: 'create_all' }, - { roles: ['5692b920d1028f01000407e6'], type: 'read_all' }, - { roles: ['5692b920d1028f01000407e6'], type: 'update_all' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'create_own' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - access: [ - { roles: [], type: 'create_all' }, - { - roles: [ - '5692b920d1028f01000407e4', - '5692b920d1028f01000407e5', - '5692b920d1028f01000407e6', - ], - type: 'read_all', - }, - { roles: [], type: 'update_all' }, - { roles: [], type: 'delete_all' }, - { roles: [], type: 'create_own' }, - { roles: [], type: 'read_own' }, - { roles: [], type: 'update_own' }, - { roles: [], type: 'delete_own' }, - { roles: [], type: 'team_read' }, - { roles: [], type: 'team_write' }, - { roles: [], type: 'team_admin' }, - ], - tags: [], - type: 'form', - revisions: '', - _vid: 0, - settings: {}, + _id: '59121aaaed27e70083924f5b', + machineName: 'examples:e', + modified: '2021-06-08T21:04:52.339Z', + title: 'E', + display: 'form', + name: 'e', + path: 'e', + project: '5692b91fd1028f01000407e3', + created: '2017-05-09T19:38:18.503Z', + components: [ + { + key: 'content', + input: false, + html: '

You are on Page E!

\n', + type: 'content', + tableView: false, + label: 'Content', + }, + { + label: 'Total', + mask: false, + spellcheck: true, + disabled: true, + tableView: true, + delimiter: false, + requireDecimal: false, + inputFormat: 'plain', + customDefaultValue: 'value = instance.root.data.score;', + calculateValue: { '+': [{ var: 'data.totalScore' }, { var: 'data.score' }] }, + key: 'total', + type: 'number', + inputType: 'number', + input: true, + }, + { + disabled: true, + type: 'number', + key: 'score', + label: 'Score', + inputType: 'number', + tableView: true, + input: true, + calculateValue: { + if: [ + { '==': [{ var: 'data.points' }, 'plus1'] }, + 1, + { '==': [{ var: 'data.points' }, 'plus2'] }, + 2, + { '==': [{ var: 'data.points' }, 'plus3'] }, + 3, + 0, + ], + }, + }, + { + input: true, + tableView: true, + label: 'Points', + key: 'points', + values: [ + { value: 'plus1', label: '+ 1' }, + { value: 'plus2', label: '+ 2' }, + { value: 'plus3', label: '+ 3' }, + { value: 'noChange', label: 'No Change' }, + ], + type: 'radio', + }, + { + input: true, + tableView: true, + label: 'Which page would you like to go to next?', + key: 'nextPage', + data: { + values: [ + { value: 'pageA', label: 'A' }, + { value: 'pageB', label: 'B' }, + { value: 'pageC', label: 'C' }, + { value: 'pageD', label: 'D' }, + { value: 'pageE', label: 'E' }, + { label: "I'm Done", value: 'done' }, + ], + }, + type: 'select', + lockKey: true, + }, + { input: true, label: 'Submit', tableView: false, key: 'submit', type: 'button' }, + ], + owner: '553dbfc08d22d5cb1a7024f2', + submissionAccess: [ + { roles: ['5692b920d1028f01000407e6'], type: 'create_all' }, + { roles: ['5692b920d1028f01000407e6'], type: 'read_all' }, + { roles: ['5692b920d1028f01000407e6'], type: 'update_all' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'create_own' }, + { roles: [], type: 'read_own' }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + access: [ + { roles: [], type: 'create_all' }, + { + roles: ['5692b920d1028f01000407e4', '5692b920d1028f01000407e5', '5692b920d1028f01000407e6'], + type: 'read_all', + }, + { roles: [], type: 'update_all' }, + { roles: [], type: 'delete_all' }, + { roles: [], type: 'create_own' }, + { roles: [], type: 'read_own' }, + { roles: [], type: 'update_own' }, + { roles: [], type: 'delete_own' }, + { roles: [], type: 'team_read' }, + { roles: [], type: 'team_write' }, + { roles: [], type: 'team_admin' }, + ], + tags: [], + type: 'form', + revisions: '', + _vid: 0, + settings: {}, }; export const simpleNestedForm = { - display: 'form', - components: [ + display: 'form', + components: [ + { + collapsible: false, + key: 'panel', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + components: [ { - collapsible: false, - key: 'panel', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - components: [ - { - label: 'Data Grid', - reorder: false, - addAnotherPosition: 'bottom', - layoutFixed: false, - enableRowGroups: false, - initEmpty: false, - tableView: false, - defaultValue: [{}], - key: 'dataGrid', - type: 'datagrid', - input: true, - components: [ - { - label: 'Required Field', - applyMaskOn: 'change', - tableView: true, - validate: { - required: true, - }, - key: 'requiredField', - type: 'textfield', - input: true, - }, - { - label: 'Maximum Length', - applyMaskOn: 'change', - tableView: true, - validate: { - maxLength: 5, - }, - key: 'maximumLength', - type: 'textfield', - input: true, - }, - { - label: 'Numbers Only', - applyMaskOn: 'change', - tableView: true, - validate: { - pattern: '\\d', - }, - key: 'numbersOnly', - type: 'textfield', - input: true, - }, - ], - }, - { - label: 'Two Validations', - applyMaskOn: 'change', - tableView: true, - validate: { - pattern: '\\d', - minLength: 5, - }, - key: 'twoValidations', - type: 'textfield', - input: true, - }, - ], + label: 'Data Grid', + reorder: false, + addAnotherPosition: 'bottom', + layoutFixed: false, + enableRowGroups: false, + initEmpty: false, + tableView: false, + defaultValue: [{}], + key: 'dataGrid', + type: 'datagrid', + input: true, + components: [ + { + label: 'Required Field', + applyMaskOn: 'change', + tableView: true, + validate: { + required: true, + }, + key: 'requiredField', + type: 'textfield', + input: true, + }, + { + label: 'Maximum Length', + applyMaskOn: 'change', + tableView: true, + validate: { + maxLength: 5, + }, + key: 'maximumLength', + type: 'textfield', + input: true, + }, + { + label: 'Numbers Only', + applyMaskOn: 'change', + tableView: true, + validate: { + pattern: '\\d', + }, + key: 'numbersOnly', + type: 'textfield', + input: true, + }, + ], }, { - type: 'button', - label: 'Submit', - key: 'submit', - disableOnInvalid: true, - input: true, - tableView: false, + label: 'Two Validations', + applyMaskOn: 'change', + tableView: true, + validate: { + pattern: '\\d', + minLength: 5, + }, + key: 'twoValidations', + type: 'textfield', + input: true, }, - ], + ], + }, + { + type: 'button', + label: 'Submit', + key: 'submit', + disableOnInvalid: true, + input: true, + tableView: false, + }, + ], }; diff --git a/src/process/validation/rules/__tests__/fixtures/util.ts b/src/process/validation/rules/__tests__/fixtures/util.ts index 8de1bb13..7f704b8f 100644 --- a/src/process/validation/rules/__tests__/fixtures/util.ts +++ b/src/process/validation/rules/__tests__/fixtures/util.ts @@ -1,27 +1,31 @@ -import { get } from "lodash"; -import { Component, DataObject, Form, ProcessorType, ValidationContext } from "types"; +import { get } from 'lodash'; +import { Component, DataObject, ProcessorType, ValidationContext } from 'types'; -export const generateProcessorContext = (component: Component, data: DataObject, form?: any): ValidationContext => { - const path = component.key; - const value = get(data, path); - return { - component, - data, - form, - scope: {errors: []}, - row: data, - path: component.key, - value, - config: { - server: true - }, - fetch: (url: string, options?: RequestInit | undefined) => { - return Promise.resolve({ - ok: true, - json: () => Promise.resolve([]), - text: () => Promise.resolve('') - }); - }, - processor: ProcessorType.Validate, - }; -} +export const generateProcessorContext = ( + component: Component, + data: DataObject, + form?: any, +): ValidationContext => { + const path = component.key; + const value = get(data, path); + return { + component, + data, + form, + scope: { errors: [] }, + row: data, + path: component.key, + value, + config: { + server: true, + }, + fetch: () => { + return Promise.resolve({ + ok: true, + json: () => Promise.resolve([]), + text: () => Promise.resolve(''), + }); + }, + processor: ProcessorType.Validate, + }; +}; diff --git a/src/process/validation/rules/__tests__/validateAvailableItems.test.ts b/src/process/validation/rules/__tests__/validateAvailableItems.test.ts index cc5beaba..4b530d88 100644 --- a/src/process/validation/rules/__tests__/validateAvailableItems.test.ts +++ b/src/process/validation/rules/__tests__/validateAvailableItems.test.ts @@ -3,559 +3,568 @@ import { expect } from 'chai'; import { FieldError } from 'error'; import { RadioComponent, SelectComponent } from 'types'; import { - simpleRadioField, - simpleSelectBoxes, - simpleTextField, - simpleSelectOptions, + simpleRadioField, + simpleSelectBoxes, + simpleTextField, + simpleSelectOptions, } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateAvailableItems, validateAvailableItemsSync } from '../validateAvailableItems'; -it('Validating a component without the available items validation parameter will return null', async () => { +describe('validateAvailableItems', function () { + it('Validating a component without the available items validation parameter will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple select boxes component without the available items validation parameter will return null', async () => { + it('Validating a simple select boxes component without the available items validation parameter will return null', async function () { const component = simpleSelectBoxes; const data = { - component: { - foo: false, - bar: false, - baz: false, - biz: false, - }, + component: { + foo: false, + bar: false, + baz: false, + biz: false, + }, }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple radio component without the available items validation parameter will return null', async () => { + it('Validating a simple radio component without the available items validation parameter will return null', async function () { const component = simpleRadioField; const data = { - component: 'bar', + component: 'bar', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple radio component with the available items validation parameter will return null if the item is valid', async () => { + it('Validating a simple radio component with the available items validation parameter will return null if the item is valid', async function () { const component: RadioComponent = { - ...simpleRadioField, - validate: { onlyAvailableItems: true }, + ...simpleRadioField, + validate: { onlyAvailableItems: true }, }; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidOption'); -}); + }); -it('Validating a simple static values select component without the available items validation parameter will return null', async () => { + it('Validating a simple static values select component without the available items validation parameter will return null', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'values', - data: { - values: [ - { label: 'foo', value: 'foo' }, - { label: 'bar', value: 'bar' }, - { label: 'baz', value: 'baz' }, - { label: 'baz', value: 'baz' }, - ], - }, + ...simpleSelectOptions, + dataSrc: 'values', + data: { + values: [ + { label: 'foo', value: 'foo' }, + { label: 'bar', value: 'bar' }, + { label: 'baz', value: 'baz' }, + { label: 'baz', value: 'baz' }, + ], + }, }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple static values select component with the available items validation parameter will return null if the selected item is valid', async () => { + it('Validating a simple static values select component with the available items validation parameter will return null if the selected item is valid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'values', - data: { - values: [ - { label: 'foo', value: 'foo' }, - { label: 'bar', value: 'bar' }, - { label: 'baz', value: 'baz' }, - { label: 'baz', value: 'baz' }, - ], - }, - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'values', + data: { + values: [ + { label: 'foo', value: 'foo' }, + { label: 'bar', value: 'bar' }, + { label: 'baz', value: 'baz' }, + { label: 'baz', value: 'baz' }, + ], + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple static values select component with the available items validation parameter will return null if the selected item is valid and dataSrc is not specified', async () => { + it('Validating a simple static values select component with the available items validation parameter will return null if the selected item is valid and dataSrc is not specified', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: undefined, - data: { - values: [ - { label: 'foo', value: 'foo' }, - { label: 'bar', value: 'bar' }, - { label: 'baz', value: 'baz' }, - { label: 'baz', value: 'baz' }, - ], - }, - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: undefined, + data: { + values: [ + { label: 'foo', value: 'foo' }, + { label: 'bar', value: 'bar' }, + { label: 'baz', value: 'baz' }, + { label: 'baz', value: 'baz' }, + ], + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple static values select component with the available items validation parameter set to false will return null', async () => { - + it('Validating a simple static values select component with the available items validation parameter set to false will return null', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'values', - data: { - values: [ - { label: 'foo', value: 'foo' }, - { label: 'bar', value: 'bar' } - ], - }, - validate: { onlyAvailableItems: false }, + ...simpleSelectOptions, + dataSrc: 'values', + data: { + values: [ + { label: 'foo', value: 'foo' }, + { label: 'bar', value: 'bar' }, + ], + }, + validate: { onlyAvailableItems: false }, }; const data = { - component: 'baz', + component: 'baz', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple URL select component without the available items validation parameter will return null', async () => { + it('Validating a simple URL select component without the available items validation parameter will return null', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'url', - data: { - url: 'http://localhost:8080/numbers', - headers: [], - }, + ...simpleSelectOptions, + dataSrc: 'url', + data: { + url: 'http://localhost:8080/numbers', + headers: [], + }, }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple URL select component synchronously will return null', async () => { + it('Validating a simple URL select component synchronously will return null', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'url', - data: { - url: 'http://localhost:8080/numbers', - headers: [], - }, - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'url', + data: { + url: 'http://localhost:8080/numbers', + headers: [], + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data); const result = validateAvailableItemsSync(context); expect(result).to.equal(null); -}); + }); -it('Validating a multiple URL select component synchronously will return null', async () => { + it('Validating a multiple URL select component synchronously will return null', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'url', - data: { - url: 'http://localhost:8080/numbers', - headers: [], - }, - multiple: true, - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'url', + data: { + url: 'http://localhost:8080/numbers', + headers: [], + }, + multiple: true, + validate: { onlyAvailableItems: true }, }; const data = { - component: ['foo'], + component: ['foo'], }; const context = generateProcessorContext(component, data); const result = validateAvailableItemsSync(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple JSON select component (string JSON) without the available items validation parameter will return null', async () => { + it('Validating a simple JSON select component (string JSON) without the available items validation parameter will return null', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'json', - data: { - json: '["foo", "bar", "baz", "biz"]', - }, + ...simpleSelectOptions, + dataSrc: 'json', + data: { + json: '["foo", "bar", "baz", "biz"]', + }, }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple JSON select component (string JSON) with the available items validation parameter will return a FieldError if the item is invalid', async () => { + it('Validating a simple JSON select component (string JSON) with the available items validation parameter will return a FieldError if the item is invalid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'json', - data: { - json: '["foo", "bar", "baz", "biz"]', - }, - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'json', + data: { + json: '["foo", "bar", "baz", "biz"]', + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidOption'); -}); + }); -it('Validating a simple JSON select component (string JSON) with the available items validation parameter will return null if the item is valid', async () => { + it('Validating a simple JSON select component (string JSON) with the available items validation parameter will return null if the item is valid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'json', - data: { - json: '["foo", "bar", "baz", "biz"]', - }, - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'json', + data: { + json: '["foo", "bar", "baz", "biz"]', + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple JSON select component (nested string JSON) with the available items validation parameter will return null if the item is valid', async () => { + it('Validating a simple JSON select component (nested string JSON) with the available items validation parameter will return null if the item is valid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'json', - data: { - json: '[{"foo": "foo", "bar": "bar"}, {"baz": "baz", "biz": "biz"}]', - }, - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'json', + data: { + json: '[{"foo": "foo", "bar": "bar"}, {"baz": "baz", "biz": "biz"}]', + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: { foo: 'foo', bar: 'bar' }, + component: { foo: 'foo', bar: 'bar' }, }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple JSON select component (nested string JSON) with the available items validation parameter will return a FieldError if the item is invalid', async () => { + it('Validating a simple JSON select component (nested string JSON) with the available items validation parameter will return a FieldError if the item is invalid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'json', - data: { - json: '[{"foo": "foo", "bar": "bar"}, {"baz": "baz", "biz": "biz"}]', - }, - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'json', + data: { + json: '[{"foo": "foo", "bar": "bar"}, {"baz": "baz", "biz": "biz"}]', + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: { foo: 'bar', bar: 'baz' }, + component: { foo: 'bar', bar: 'baz' }, }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidOption'); -}); + }); -it('Validating a simple JSON select component (nested string JSON with valueProperty) with the available items validation parameter will return a FieldError if the item is invalid', async () => { + it('Validating a simple JSON select component (nested string JSON with valueProperty) with the available items validation parameter will return a FieldError if the item is invalid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'json', - data: { - json: '[{"foo": "foo", "bar": "bar"}, {"baz": "baz", "biz": "biz"}]', - }, - valueProperty: 'foo', - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'json', + data: { + json: '[{"foo": "foo", "bar": "bar"}, {"baz": "baz", "biz": "biz"}]', + }, + valueProperty: 'foo', + validate: { onlyAvailableItems: true }, }; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidOption'); -}); + }); -it('Validating a simple JSON select component (nested string JSON with valueProperty) with the available items validation parameter will return null if the item is valid', async () => { + it('Validating a simple JSON select component (nested string JSON with valueProperty) with the available items validation parameter will return null if the item is valid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'json', - data: { - json: '[{"foo": "foo", "bar": "bar"}, {"baz": "baz", "biz": "biz"}]', - }, - valueProperty: 'foo', - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'json', + data: { + json: '[{"foo": "foo", "bar": "bar"}, {"baz": "baz", "biz": "biz"}]', + }, + valueProperty: 'foo', + validate: { onlyAvailableItems: true }, }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple JSON select component (actual JSON) without the available items validation parameter will return null', async () => { + it('Validating a simple JSON select component (actual JSON) without the available items validation parameter will return null', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'json', - data: { - json: ['foo', 'bar', 'baz', 'biz'], - }, + ...simpleSelectOptions, + dataSrc: 'json', + data: { + json: ['foo', 'bar', 'baz', 'biz'], + }, }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple JSON select component (actual JSON) with the available items validation parameter will return a FieldError if the selected item is invalid', async () => { + it('Validating a simple JSON select component (actual JSON) with the available items validation parameter will return a FieldError if the selected item is invalid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'json', - data: { - json: ['foo', 'bar', 'baz', 'biz'], - }, - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'json', + data: { + json: ['foo', 'bar', 'baz', 'biz'], + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidOption'); -}); + }); -it('Validating a simple JSON select component (actual JSON) with the available items validation parameter will return null if the selected item is valid', async () => { + it('Validating a simple JSON select component (actual JSON) with the available items validation parameter will return null if the selected item is valid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'json', - data: { - json: ['foo', 'bar', 'baz', 'biz'], - }, - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'json', + data: { + json: ['foo', 'bar', 'baz', 'biz'], + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple JSON select component (nested actual JSON) with the available items validation parameter will return a FieldError if the selected item is invalid', async () => { + it('Validating a simple JSON select component (nested actual JSON) with the available items validation parameter will return a FieldError if the selected item is invalid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'json', - data: { - json: [ - { foo: 'foo', bar: 'bar' }, - { baz: 'baz', biz: 'biz' }, - ], - }, - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'json', + data: { + json: [ + { foo: 'foo', bar: 'bar' }, + { baz: 'baz', biz: 'biz' }, + ], + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: { foo: 'baz', bar: 'biz' }, + component: { foo: 'baz', bar: 'biz' }, }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidOption'); -}); + }); -it('Validating a simple JSON select component (nested actual JSON) with the available items validation parameter will return null if the selected item is valid', async () => { + it('Validating a simple JSON select component (nested actual JSON) with the available items validation parameter will return null if the selected item is valid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'json', - data: { - json: [ - { foo: 'foo', bar: 'bar' }, - { baz: 'baz', biz: 'biz' }, - ], - }, - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'json', + data: { + json: [ + { foo: 'foo', bar: 'bar' }, + { baz: 'baz', biz: 'biz' }, + ], + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: { foo: 'foo', bar: 'bar' }, + component: { foo: 'foo', bar: 'bar' }, }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple JSON select component (nested actual JSON with valueProperty) with the available items validation parameter will return a FieldError if the selected item is invalid', async () => { + it('Validating a simple JSON select component (nested actual JSON with valueProperty) with the available items validation parameter will return a FieldError if the selected item is invalid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'json', - data: { - json: [ - { foo: 'foo', bar: 'bar' }, - { foo: 'baz', bar: 'biz' }, - ], - }, - validate: { onlyAvailableItems: true }, - valueProperty: 'foo', + ...simpleSelectOptions, + dataSrc: 'json', + data: { + json: [ + { foo: 'foo', bar: 'bar' }, + { foo: 'baz', bar: 'biz' }, + ], + }, + validate: { onlyAvailableItems: true }, + valueProperty: 'foo', }; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidOption'); -}); + }); -it('Validating a simple JSON select component (nested actual JSON with valueProperty) with the available items validation parameter will return null if the selected item is valid', async () => { + it('Validating a simple JSON select component (nested actual JSON with valueProperty) with the available items validation parameter will return null if the selected item is valid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'json', - data: { - json: [ - { foo: 'foo', bar: 'bar' }, - { foo: 'baz', bar: 'biz' }, - ], - }, - validate: { onlyAvailableItems: true }, - valueProperty: 'foo', + ...simpleSelectOptions, + dataSrc: 'json', + data: { + json: [ + { foo: 'foo', bar: 'bar' }, + { foo: 'baz', bar: 'biz' }, + ], + }, + validate: { onlyAvailableItems: true }, + valueProperty: 'foo', }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data); const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple radio component with url data source with the available items validation parameter will return null if the item is valid', async () => { + it('Validating a simple radio component with url data source with the available items validation parameter will return null if the item is valid', async function () { const component: RadioComponent = { - ...simpleRadioField, - dataSrc: 'url', - data: { - url: 'http://localhost:8080/numbers', - headers: [], - }, - validate: { onlyAvailableItems: true }, + ...simpleRadioField, + dataSrc: 'url', + data: { + url: 'http://localhost:8080/numbers', + headers: [], + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: '2', + component: '2', }; - + const context = generateProcessorContext(component, data); - context.fetch = (url: string, options?: RequestInit | undefined) => { - return Promise.resolve({ - ok: true, - json: () => Promise.resolve(['1', '2', '3']) - }); + context.fetch = () => { + return Promise.resolve({ + ok: true, + json: () => Promise.resolve(['1', '2', '3']), + }); }; const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple radio component with url data source with the available items validation parameter will return FieldError if the item is invalid', async () => { + it('Validating a simple radio component with url data source with the available items validation parameter will return FieldError if the item is invalid', async function () { const component: RadioComponent = { - ...simpleRadioField, - dataSrc: 'url', - data: { - url: 'http://localhost:8080/numbers', - headers: [], - }, - validate: { onlyAvailableItems: true }, + ...simpleRadioField, + dataSrc: 'url', + data: { + url: 'http://localhost:8080/numbers', + headers: [], + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: '4', + component: '4', }; - + const context = generateProcessorContext(component, data); - context.fetch = (url: string, options?: RequestInit | undefined) => { - return Promise.resolve({ - ok: true, - json: () => Promise.resolve(['1', '2', '3']) - }); + context.fetch = () => { + return Promise.resolve({ + ok: true, + json: () => Promise.resolve(['1', '2', '3']), + }); }; const result = await validateAvailableItems(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidOption'); -}); + }); -it('Validating a simple select component with url data source with the available items validation parameter will return null if the item is valid', async () => { + it('Validating a simple select component with url data source with the available items validation parameter will return null if the item is valid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'url', - data: { - url: 'http://localhost:8080/numbers', - headers: [], - }, - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'url', + data: { + url: 'http://localhost:8080/numbers', + headers: [], + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: {'id': 'opt_1', 'value': 1}, + component: { id: 'opt_1', value: 1 }, }; - + const context = generateProcessorContext(component, data); - context.fetch = (url: string, options?: RequestInit | undefined) => { - return Promise.resolve({ - ok: true, - json: () => Promise.resolve([{'id': 'opt_1', 'value': 1}, {'id': 'opt_2', 'value': 2}]) - }); + context.fetch = () => { + return Promise.resolve({ + ok: true, + json: () => + Promise.resolve([ + { id: 'opt_1', value: 1 }, + { id: 'opt_2', value: 2 }, + ]), + }); }; const result = await validateAvailableItems(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple select component with url data source with the available items validation parameter will return FieldError if the item is invalid', async () => { + it('Validating a simple select component with url data source with the available items validation parameter will return FieldError if the item is invalid', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'url', - data: { - url: 'http://localhost:8080/numbers', - headers: [], - }, - validate: { onlyAvailableItems: true }, + ...simpleSelectOptions, + dataSrc: 'url', + data: { + url: 'http://localhost:8080/numbers', + headers: [], + }, + validate: { onlyAvailableItems: true }, }; const data = { - component: {'id': 'opt_3', 'value': 3}, + component: { id: 'opt_3', value: 3 }, }; - + const context = generateProcessorContext(component, data); - context.fetch = (url: string, options?: RequestInit | undefined) => { - return Promise.resolve({ - ok: true, - json: () => Promise.resolve([{'id': 'opt_1', 'value': 1}, {'id': 'opt_2', 'value': 2}]) - }); + context.fetch = () => { + return Promise.resolve({ + ok: true, + json: () => + Promise.resolve([ + { id: 'opt_1', value: 1 }, + { id: 'opt_2', value: 2 }, + ]), + }); }; const result = await validateAvailableItems(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidOption'); -}); \ No newline at end of file + }); +}); diff --git a/src/process/validation/rules/__tests__/validateCustom.test.ts b/src/process/validation/rules/__tests__/validateCustom.test.ts index d1de423e..94a2fef9 100644 --- a/src/process/validation/rules/__tests__/validateCustom.test.ts +++ b/src/process/validation/rules/__tests__/validateCustom.test.ts @@ -6,49 +6,51 @@ import { simpleTextField } from './fixtures/components'; import { validateCustom } from '../validateCustom'; import { generateProcessorContext } from './fixtures/util'; -it('A simple custom validation will correctly be interpolated', async () => { +describe('validateCustom', function () { + it('A simple custom validation will correctly be interpolated', async function () { const component: TextFieldComponent = { - ...simpleTextField, - validate: { - custom: 'valid = "Invalid entry"', - }, + ...simpleTextField, + validate: { + custom: 'valid = "Invalid entry"', + }, }; const data = { - component: 'any thing', - } + component: 'any thing', + }; const context = generateProcessorContext(component, data); const result = await validateCustom(context); expect(result).to.be.instanceOf(FieldError); expect(result && result.errorKeyOrMessage).to.equal('Invalid entry'); -}); + }); -it('A custom validation that includes data will correctly be interpolated', async () => { + it('A custom validation that includes data will correctly be interpolated', async function () { const component: TextFieldComponent = { - ...simpleTextField, - validate: { - custom: 'valid = data.simpleComponent === "any thing" ? true : "Invalid entry"', - }, + ...simpleTextField, + validate: { + custom: 'valid = data.simpleComponent === "any thing" ? true : "Invalid entry"', + }, }; const data = { - simpleComponent: 'any thing', - } + simpleComponent: 'any thing', + }; const context = generateProcessorContext(component, data); const result = await validateCustom(context); expect(result).to.equal(null); -}); + }); -it('A custom validation of empty component data will still validate', async () => { + it('A custom validation of empty component data will still validate', async function () { const component: TextFieldComponent = { - ...simpleTextField, - validate: { - custom: 'valid = data.simpleComponent === "any thing" ? true : "Invalid entry"', - }, + ...simpleTextField, + validate: { + custom: 'valid = data.simpleComponent === "any thing" ? true : "Invalid entry"', + }, }; const data = { - simpleComponent: '', + simpleComponent: '', }; const context = generateProcessorContext(component, data); const result = await validateCustom(context); expect(result).to.be.instanceOf(FieldError); expect(result && result.errorKeyOrMessage).to.equal('Invalid entry'); + }); }); diff --git a/src/process/validation/rules/__tests__/validateDate.test.ts b/src/process/validation/rules/__tests__/validateDate.test.ts index be023f89..f1cac99c 100644 --- a/src/process/validation/rules/__tests__/validateDate.test.ts +++ b/src/process/validation/rules/__tests__/validateDate.test.ts @@ -5,80 +5,82 @@ import { calendarTextField, simpleDateTimeField, simpleTextField } from './fixtu import { validateDate } from '../validateDate'; import { generateProcessorContext } from './fixtures/util'; -it('Validating a component without a date/time concern will return null', async () => { +describe('validateDate', function () { + it('Validating a component without a date/time concern will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateDate(context); expect(result).to.equal(null); -}); + }); -it('Validating a date/time component with no data will return null', async () => { + it('Validating a date/time component with no data will return null', async function () { const component = simpleDateTimeField; const data = {}; const context = generateProcessorContext(component, data); const result = await validateDate(context); expect(result).to.equal(null); -}); + }); -it('Validating a date/time component with an invalid date string value will return a FieldError', async () => { + it('Validating a date/time component with an invalid date string value will return a FieldError', async function () { const component = simpleDateTimeField; const data = { - component: 'hello, world!', + component: 'hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateDate(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidDate'); -}); + }); -it('Validating a date/time component with an valid date string value will return null', async () => { + it('Validating a date/time component with an valid date string value will return null', async function () { const component = simpleDateTimeField; const data = { - component: '2023-03-09T12:00:00-06:00', + component: '2023-03-09T12:00:00-06:00', }; const context = generateProcessorContext(component, data); const result = await validateDate(context); expect(result).to.equal(null); -}); + }); -it('Validating a date/time component with an invalid Date object will return a FieldError', async () => { + it('Validating a date/time component with an invalid Date object will return a FieldError', async function () { const component = simpleDateTimeField; const data = { - component: new Date('Hello, world!'), + component: new Date('Hello, world!'), }; const context = generateProcessorContext(component, data); const result = await validateDate(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidDate'); -}); + }); -it('Validating a date/time component with a valid Date object will return null', async () => { + it('Validating a date/time component with a valid Date object will return null', async function () { const component = simpleDateTimeField; const data = { - component: new Date(), + component: new Date(), }; const context = generateProcessorContext(component, data); const result = await validateDate(context); expect(result).to.equal(null); -}); + }); -it('Validating a textField calendar picker component with no data will return null', async () => { + it('Validating a textField calendar picker component with no data will return null', async function () { const component = calendarTextField; const data = {}; const context = generateProcessorContext(component, data); const result = await validateDate(context); expect(result).to.equal(null); -}); + }); -it('Textfield calendar picker component date values should not be validated and return null', async () => { + it('Textfield calendar picker component date values should not be validated and return null', async function () { const component = calendarTextField; const data = { - component: 'hello, world!', + component: 'hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateDate(context); expect(result).to.be.equal(null); + }); }); diff --git a/src/process/validation/rules/__tests__/validateDay.test.ts b/src/process/validation/rules/__tests__/validateDay.test.ts index 4a2d2e0c..f30fdce3 100644 --- a/src/process/validation/rules/__tests__/validateDay.test.ts +++ b/src/process/validation/rules/__tests__/validateDay.test.ts @@ -6,199 +6,201 @@ import { generateProcessorContext } from './fixtures/util'; import { fastCloneDeep } from 'utils'; import { validateDay } from '../validateDay'; -it('Validating a non-day component will return null', async () => { +describe('validateDay', function () { + it('Validating a non-day component will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with an invalid date string value will return a FieldError', async () => { + it('Validating a day component with an invalid date string value will return a FieldError', async function () { const component = simpleDayField; const data = { - component: 'hello, world!', + component: 'hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidDay'); -}); + }); -it('Validating a day component with an valid date string value will return null', async () => { + it('Validating a day component with an valid date string value will return null', async function () { const component = simpleDayField; const data = { - component: '03/23/2023', + component: '03/23/2023', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with an invalid Date object will return a FieldError', async () => { + it('Validating a day component with an invalid Date object will return a FieldError', async function () { const component = simpleDayField; const data = { - component: new Date('Hello, world!'), + component: new Date('Hello, world!'), }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidDay'); -}); + }); -it('Validating a day component with a valid Date object will return a field error', async () => { + it('Validating a day component with a valid Date object will return a field error', async function () { const component = simpleDayField; const data = { - component: new Date(), + component: new Date(), }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidDay'); -}); + }); -it('Validating a day component with hidden day field with an valid date string value will return null', async () => { + it('Validating a day component with hidden day field with an valid date string value will return null', async function () { const component = fastCloneDeep(simpleDayField); component.fields.day.hide = true; const data = { - component: '03/2023', + component: '03/2023', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with hidden day field with invalid date will return a field error', async () => { + it('Validating a day component with hidden day field with invalid date will return a field error', async function () { const component = fastCloneDeep(simpleDayField); component.fields.day.hide = true; const data = { - component: '13/2023', + component: '13/2023', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidDay'); -}); + }); -it('Validating a day component with hidden month field with an valid date string value will return null', async () => { + it('Validating a day component with hidden month field with an valid date string value will return null', async function () { const component = fastCloneDeep(simpleDayField); component.fields.month.hide = true; const data = { - component: '23/2023', + component: '23/2023', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with hidden month field with invalid date will return a field error', async () => { - const component = fastCloneDeep(simpleDayField);; + it('Validating a day component with hidden month field with invalid date will return a field error', async function () { + const component = fastCloneDeep(simpleDayField); component.fields.month.hide = true; const data = { - component: '130/2023', + component: '130/2023', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidDay'); -}); + }); -it('Validating a day component with hidden year field with an valid date string value will return null', async () => { + it('Validating a day component with hidden year field with an valid date string value will return null', async function () { const component = fastCloneDeep(simpleDayField); component.fields.year.hide = true; const data = { - component: '01/23', + component: '01/23', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with hidden year field with invalid date will return a field error', async () => { + it('Validating a day component with hidden year field with invalid date will return a field error', async function () { const component = fastCloneDeep(simpleDayField); component.fields.year.hide = true; const data = { - component: '13/23', + component: '13/23', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidDay'); -}); + }); -it('Validating a day component with hidden year and month fields with an valid date string value will return null', async () => { + it('Validating a day component with hidden year and month fields with an valid date string value will return null', async function () { const component = fastCloneDeep(simpleDayField); component.fields.year.hide = true; component.fields.month.hide = true; const data = { - component: '23', + component: '23', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with hidden year and month fields with invalid date will return a field error', async () => { + it('Validating a day component with hidden year and month fields with invalid date will return a field error', async function () { const component = fastCloneDeep(simpleDayField); component.fields.year.hide = true; component.fields.month.hide = true; const data = { - component: '123', + component: '123', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidDay'); -}); + }); -it('Validating a day component with hidden year and day fields with an valid date string value will return null', async () => { + it('Validating a day component with hidden year and day fields with an valid date string value will return null', async function () { const component = fastCloneDeep(simpleDayField); component.fields.year.hide = true; component.fields.day.hide = true; const data = { - component: '10', + component: '10', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with hidden year and day fields with invalid date will return a field error', async () => { + it('Validating a day component with hidden year and day fields with invalid date will return a field error', async function () { const component = fastCloneDeep(simpleDayField); component.fields.year.hide = true; component.fields.day.hide = true; const data = { - component: '22', + component: '22', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidDay'); -}); + }); -it('Validating a day component with hidden day and month fields with an valid date string value will return null', async () => { + it('Validating a day component with hidden day and month fields with an valid date string value will return null', async function () { const component = fastCloneDeep(simpleDayField); component.fields.month.hide = true; component.fields.day.hide = true; const data = { - component: '2024', + component: '2024', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with hidden day and month fields with invalid date will return a field error', async () => { + it('Validating a day component with hidden day and month fields with invalid date will return a field error', async function () { const component = fastCloneDeep(simpleDayField); component.fields.month.hide = true; component.fields.day.hide = true; const data = { - component: '100042', + component: '100042', }; const context = generateProcessorContext(component, data); const result = await validateDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('invalidDay'); + }); }); diff --git a/src/process/validation/rules/__tests__/validateEmail.test.ts b/src/process/validation/rules/__tests__/validateEmail.test.ts index f9f84678..097239ec 100644 --- a/src/process/validation/rules/__tests__/validateEmail.test.ts +++ b/src/process/validation/rules/__tests__/validateEmail.test.ts @@ -5,23 +5,25 @@ import { simpleEmailField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateEmail } from '../validateEmail'; -it('Validating a valid email will return null', async () => { +describe('validateEmail', function () { + it('Validating a valid email will return null', async function () { const component = simpleEmailField; const data = { - component: 'sales@form.io', + component: 'sales@form.io', }; const context = generateProcessorContext(component, data); const result = await validateEmail(context); expect(result).to.equal(null); -}); + }); -it('Validating an invalid email will return a FieldError', async () => { + it('Validating an invalid email will return a FieldError', async function () { const component = simpleEmailField; const data = { - component: 'salesatform.io', + component: 'salesatform.io', }; const context = generateProcessorContext(component, data); const result = await validateEmail(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.contain('invalid_email'); + }); }); diff --git a/src/process/validation/rules/__tests__/validateJson.test.ts b/src/process/validation/rules/__tests__/validateJson.test.ts index bc3c4e5c..bbb1c78e 100644 --- a/src/process/validation/rules/__tests__/validateJson.test.ts +++ b/src/process/validation/rules/__tests__/validateJson.test.ts @@ -5,130 +5,132 @@ import { simpleTextField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateJson } from '../validateJson'; -it('A simple component without JSON logic validation will return null', async () => { +describe('validateJson', function () { + it('A simple component without JSON logic validation will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateJson(context); expect(result).to.equal(null); -}); + }); -it('A simple component with JSON logic evaluation will return a FieldError if the JSON logic returns invalid', async () => { + it('A simple component with JSON logic evaluation will return a FieldError if the JSON logic returns invalid', async function () { const component = { - ...simpleTextField, - validate: { - json: { - if: [ - { - '===': [ - { - var: 'input', - }, - 'foo', - ], - }, - true, - "Input must be 'foo'", - ], + ...simpleTextField, + validate: { + json: { + if: [ + { + '===': [ + { + var: 'input', + }, + 'foo', + ], }, + true, + "Input must be 'foo'", + ], }, + }, }; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateJson(context); expect(result).to.be.instanceOf(FieldError); - expect(result?.errorKeyOrMessage).to.contain('Input must be \'foo\''); -}); + expect(result?.errorKeyOrMessage).to.contain("Input must be 'foo'"); + }); -it('A simple component with JSON logic evaluation will return null if the JSON logic returns valid', async () => { + it('A simple component with JSON logic evaluation will return null if the JSON logic returns valid', async function () { const component = { - ...simpleTextField, - validate: { - json: { - if: [ - { - '===': [ - { - var: 'input', - }, - 'foo', - ], - }, - true, - "Input must be 'foo'", - ], + ...simpleTextField, + validate: { + json: { + if: [ + { + '===': [ + { + var: 'input', + }, + 'foo', + ], }, + true, + "Input must be 'foo'", + ], }, + }, }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data); const result = await validateJson(context); expect(result).to.equal(null); -}); + }); -it('A simple component with JSON logic evaluation will validate even if the value is falsy', async () => { + it('A simple component with JSON logic evaluation will validate even if the value is falsy', async function () { const component = { - ...simpleTextField, - validate: { - json: { - if: [ - { - '===': [ - { - var: 'input', - }, - 'foo', - ], - }, - true, - "Input must be 'foo'", - ], + ...simpleTextField, + validate: { + json: { + if: [ + { + '===': [ + { + var: 'input', + }, + 'foo', + ], }, + true, + "Input must be 'foo'", + ], }, + }, }; const data = { - component: '', + component: '', }; const context = generateProcessorContext(component, data); const result = await validateJson(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.contain("Input must be 'foo'"); -}); + }); -it('Should have access to form JSON in its validation context', async () => { + it('Should have access to form JSON in its validation context', async function () { const component = { - ...simpleTextField, - validate: { - json: { - if: [ - { - '>': [ - { - var: 'form.components', - }, - 5, - ], - }, - true, - 'Form must have greater than 5 components', - ], + ...simpleTextField, + validate: { + json: { + if: [ + { + '>': [ + { + var: 'form.components', + }, + 5, + ], }, + true, + 'Form must have greater than 5 components', + ], }, + }, }; const form = { - components: [component], - } + components: [component], + }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data, form); const result = await validateJson(context); expect(result).to.be.instanceOf(FieldError); - expect(result?.errorKeyOrMessage).to.contain("Form must have greater than 5 components"); -}) + expect(result?.errorKeyOrMessage).to.contain('Form must have greater than 5 components'); + }); +}); diff --git a/src/process/validation/rules/__tests__/validateMask.test.ts b/src/process/validation/rules/__tests__/validateMask.test.ts index f01d8e19..4af7d7ed 100644 --- a/src/process/validation/rules/__tests__/validateMask.test.ts +++ b/src/process/validation/rules/__tests__/validateMask.test.ts @@ -4,44 +4,45 @@ import { simpleTextField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateMask } from '../validateMask'; -it('Validating a mask component should return a FieldError if the value does not match the mask', async () => { +describe('validateMask', function () { + it('Validating a mask component should return a FieldError if the value does not match the mask', async function () { const component = { ...simpleTextField, inputMask: '999-999-9999' }; const data = { - component: '1234', + component: '1234', }; const context = generateProcessorContext(component, data); const result = await validateMask(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('mask'); -}); + }); -it('Validating a mask component should return null if the value matches the mask', async () => { + it('Validating a mask component should return null if the value matches the mask', async function () { const component = { ...simpleTextField, inputMask: '999-999-9999' }; const data = { - component: '123-456-7890', + component: '123-456-7890', }; const context = generateProcessorContext(component, data); const result = await validateMask(context); expect(result).to.equal(null); -}); + }); -it('Validating a multi-mask component should return a FieldError if the value does not match the masks', async () => { + it('Validating a multi-mask component should return a FieldError if the value does not match the masks', async function () { const component = { - ...simpleTextField, - allowMultipleMasks: true, - inputMasks: [ - { - label: 'maskOne', - mask: '999-9999', - }, - { - label: 'maskTwo', - mask: '999-999-9999', - }, - ], + ...simpleTextField, + allowMultipleMasks: true, + inputMasks: [ + { + label: 'maskOne', + mask: '999-9999', + }, + { + label: 'maskTwo', + mask: '999-999-9999', + }, + ], }; let data = { - component: { maskName: 'maskOne', value: '14567890' }, + component: { maskName: 'maskOne', value: '14567890' }, }; let context = generateProcessorContext(component, data); let result = await validateMask(context); @@ -49,48 +50,48 @@ it('Validating a multi-mask component should return a FieldError if the value do expect(result?.errorKeyOrMessage).to.equal('mask'); data = { - component: { maskName: 'maskTwo', value: '1234567' }, + component: { maskName: 'maskTwo', value: '1234567' }, }; context = generateProcessorContext(component, data); result = await validateMask(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('mask'); -}); + }); -it('Validating a mutil-mask component should return null if the value matches the masks', async () => { + it('Validating a mutil-mask component should return null if the value matches the masks', async function () { const component = { - ...simpleTextField, - allowMultipleMasks: true, - inputMasks: [ - { - label: 'maskOne', - mask: '999-9999', - }, - { - label: 'maskTwo', - mask: '999-999-9999', - }, - ], + ...simpleTextField, + allowMultipleMasks: true, + inputMasks: [ + { + label: 'maskOne', + mask: '999-9999', + }, + { + label: 'maskTwo', + mask: '999-999-9999', + }, + ], }; let data = { - component: { maskName: 'maskOne', value: '456-7890' }, + component: { maskName: 'maskOne', value: '456-7890' }, }; let context = generateProcessorContext(component, data); let result = await validateMask(context); expect(result).to.equal(null); data = { - component: { maskName: 'maskTwo', value: '123-456-7890' }, + component: { maskName: 'maskTwo', value: '123-456-7890' }, }; context = generateProcessorContext(component, data); result = await validateMask(context); expect(result).to.equal(null); -}); + }); -it('Validating a mask component should return null if the instance contains a skipMaskValidation property', async () => { + it('Validating a mask component should return null if the instance contains a skipMaskValidation property', async function () { const component = { ...simpleTextField, inputMask: '999-999-9999' }; const data = { - component: '1234', + component: '1234', }; const context = generateProcessorContext(component, data); let result = await validateMask(context); @@ -99,20 +100,21 @@ it('Validating a mask component should return null if the instance contains a sk (context as any).instance = { skipMaskValidation: true }; result = await validateMask(context); expect(result).to.equal(null); -}); + }); -it('Validating a mask component should return null if the validate object contains a skipMaskValidation', async () => { + it('Validating a mask component should return null if the validate object contains a skipMaskValidation', async function () { const component = { - ...simpleTextField, - inputMask: '999-999-9999', - validate: { - skipMaskValidation: true, - }, + ...simpleTextField, + inputMask: '999-999-9999', + validate: { + skipMaskValidation: true, + }, }; const data = { - component: '1234', + component: '1234', }; const context = generateProcessorContext(component, data); const result = await validateMask(context); expect(result).to.equal(null); + }); }); diff --git a/src/process/validation/rules/__tests__/validateMaximumDay.test.ts b/src/process/validation/rules/__tests__/validateMaximumDay.test.ts index 6f84f59f..2209b2eb 100644 --- a/src/process/validation/rules/__tests__/validateMaximumDay.test.ts +++ b/src/process/validation/rules/__tests__/validateMaximumDay.test.ts @@ -5,65 +5,56 @@ import { simpleDayField, simpleTextField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateMaximumDay } from '../validateMaximumDay'; -it('Validating a non-day component will return null', async () => { +describe('validateMaximumDay', function () { + it('Validating a non-day component will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMaximumDay(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with a day after the maximum day will return a FieldError', async () => { + it('Validating a day component with a day after the maximum day will return a FieldError', async function () { const component = { ...simpleDayField, maxDate: '2023-04-01' }; const data = { - component: '04/02/2023', + component: '04/02/2023', }; const context = generateProcessorContext(component, data); const result = await validateMaximumDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('maxDay'); -}); + }); -it('Validating a day component with a day before the maximum day will return null', async () => { + it('Validating a day component with a day before the maximum day will return null', async function () { const component = { ...simpleDayField, maxDate: '2023-04-01' }; const data = { - component: '03/23/2023', + component: '03/23/2023', }; const context = generateProcessorContext(component, data); const result = await validateMaximumDay(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with a day after the maximum day will return a FieldError', async () => { - const component = { ...simpleDayField, maxDate: '2023-04-01' }; - const data = { - component: '04/02/2023', - }; - const context = generateProcessorContext(component, data); - const result = await validateMaximumDay(context); - expect(result).to.be.instanceOf(FieldError); - expect(result?.errorKeyOrMessage).to.equal('maxDay'); -}); - -it('Validating a day-first day component with a day after the maximum day will return a FieldError', async () => { + it('Validating a day-first day component with a day after the maximum day will return a FieldError', async function () { const component = { ...simpleDayField, dayFirst: true, maxDate: '2023-04-01' }; const data = { - component: '02/04/2023', + component: '02/04/2023', }; const context = generateProcessorContext(component, data); const result = await validateMaximumDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('maxDay'); -}); + }); -it('Validating a day-first day component with a day before the maximum day will return null', async () => { + it('Validating a day-first day component with a day before the maximum day will return null', async function () { const component = { ...simpleDayField, dayFirst: true, maxDate: '2023-04-01' }; const data = { - component: '23/03/2023', + component: '23/03/2023', }; const context = generateProcessorContext(component, data); const result = await validateMaximumDay(context); expect(result).to.equal(null); + }); }); diff --git a/src/process/validation/rules/__tests__/validateMaximumLength.test.ts b/src/process/validation/rules/__tests__/validateMaximumLength.test.ts index 2bbb8292..51be8938 100644 --- a/src/process/validation/rules/__tests__/validateMaximumLength.test.ts +++ b/src/process/validation/rules/__tests__/validateMaximumLength.test.ts @@ -5,43 +5,45 @@ import { simpleTextField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateMaximumLength } from '../validateMaximumLength'; -it('Validating a component without a maxLength property will return null', async () => { +describe('validateMaximumLength', function () { + it('Validating a component without a maxLength property will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMaximumLength(context); expect(result).to.equal(null); -}); + }); -it('Validating a component with a maxLength property and a length greater than maxLength will return a FieldError', async () => { + it('Validating a component with a maxLength property and a length greater than maxLength will return a FieldError', async function () { const component = { ...simpleTextField, validate: { maxLength: 4 } }; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMaximumLength(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('maxLength'); -}); + }); -it('Validating a component with a maxLength property and a length less than maxLength will return null', async () => { + it('Validating a component with a maxLength property and a length less than maxLength will return null', async function () { const component = { ...simpleTextField, validate: { maxLength: 4 } }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data); const result = await validateMaximumLength(context); expect(result).to.equal(null); -}); + }); -it('Validating a component with a maxLength property that is an empty string will return null', async () => { + it('Validating a component with a maxLength property that is an empty string will return null', async function () { const component = { ...simpleTextField, validate: { maxLength: 4 } }; const data = { - component: '', + component: '', }; const context = generateProcessorContext(component, data); const result = await validateMaximumLength(context); expect(result).to.equal(null); -}) + }); +}); diff --git a/src/process/validation/rules/__tests__/validateMaximumSelectedCount.test.ts b/src/process/validation/rules/__tests__/validateMaximumSelectedCount.test.ts index 05dcb75e..dbb7128e 100644 --- a/src/process/validation/rules/__tests__/validateMaximumSelectedCount.test.ts +++ b/src/process/validation/rules/__tests__/validateMaximumSelectedCount.test.ts @@ -5,73 +5,75 @@ import { simpleSelectBoxes, simpleTextField } from './fixtures/components'; import { validateMaximumSelectedCount } from '../validateMaximumSelectedCount'; import { generateProcessorContext } from './fixtures/util'; -it('Validting a non-select boxes component will return null', async () => { +describe('validateMaximumSelectedCount', function () { + it('Validting a non-select boxes component will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMaximumSelectedCount(context); expect(result).to.equal(null); -}); + }); -it('Validating a select boxes component without maxSelectedCount will return null', async () => { + it('Validating a select boxes component without maxSelectedCount will return null', async function () { const component = simpleSelectBoxes; const data = { - component: { - foo: true, - bar: true, - baz: false, - biz: false, - }, + component: { + foo: true, + bar: true, + baz: false, + biz: false, + }, }; const context = generateProcessorContext(component, data); const result = await validateMaximumSelectedCount(context); expect(result).to.equal(null); -}); + }); -it('Validating a select boxes component where the number of selected fields is greater than maxSelectedCount will return a FieldError', async () => { + it('Validating a select boxes component where the number of selected fields is greater than maxSelectedCount will return a FieldError', async function () { const component = { ...simpleSelectBoxes, validate: { maxSelectedCount: 1 } }; const data = { - component: { - foo: true, - bar: true, - baz: false, - biz: false, - }, + component: { + foo: true, + bar: true, + baz: false, + biz: false, + }, }; const context = generateProcessorContext(component, data); const result = await validateMaximumSelectedCount(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.contain('maxSelectedCount'); -}); + }); -it('Validating a select boxes component where the number of selected fields is equal to maxSelectedCount will return null', async () => { + it('Validating a select boxes component where the number of selected fields is equal to maxSelectedCount will return null', async function () { const component = { ...simpleSelectBoxes, validate: { maxSelectedCount: 1 } }; const data = { - component: { - foo: true, - bar: false, - baz: false, - biz: false, - }, + component: { + foo: true, + bar: false, + baz: false, + biz: false, + }, }; const context = generateProcessorContext(component, data); const result = await validateMaximumSelectedCount(context); expect(result).to.equal(null); -}); + }); -it('Validating a select boxes component where the number of selected fields is less than maxSelectedCount will return null', async () => { + it('Validating a select boxes component where the number of selected fields is less than maxSelectedCount will return null', async function () { const component = { ...simpleSelectBoxes, validate: { maxSelectedCount: 2 } }; const data = { - component: { - foo: true, - bar: false, - baz: false, - biz: false, - }, + component: { + foo: true, + bar: false, + baz: false, + biz: false, + }, }; const context = generateProcessorContext(component, data); const result = await validateMaximumSelectedCount(context); expect(result).to.equal(null); + }); }); diff --git a/src/process/validation/rules/__tests__/validateMaximumValue.test.ts b/src/process/validation/rules/__tests__/validateMaximumValue.test.ts index 6a35e558..169d91d2 100644 --- a/src/process/validation/rules/__tests__/validateMaximumValue.test.ts +++ b/src/process/validation/rules/__tests__/validateMaximumValue.test.ts @@ -5,53 +5,55 @@ import { simpleNumberField, simpleTextField } from './fixtures/components'; import { validateMaximumValue } from '../validateMaximumValue'; import { generateProcessorContext } from './fixtures/util'; -it('Validating a component without the max property will return null', async () => { +describe('validateMaximumValue', function () { + it('Validating a component without the max property will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMaximumValue(context); expect(result).to.equal(null); -}); + }); -it('Validating a number component without the max property will return null', async () => { + it('Validating a number component without the max property will return null', async function () { const component = simpleNumberField; const data = { - component: 3, + component: 3, }; const context = generateProcessorContext(component, data); const result = await validateMaximumValue(context); expect(result).to.equal(null); -}); + }); -it('Validating a number component that contains the max property will return null if the value is less than the maximum', async () => { + it('Validating a number component that contains the max property will return null if the value is less than the maximum', async function () { const component = { ...simpleNumberField, validate: { max: 50 } }; const data = { - component: 35, + component: 35, }; const context = generateProcessorContext(component, data); const result = await validateMaximumValue(context); expect(result).to.equal(null); -}); + }); -it('Validating a number component that contains the max property will return a FieldError if the value is greater than the maximum', async () => { + it('Validating a number component that contains the max property will return a FieldError if the value is greater than the maximum', async function () { const component = { ...simpleNumberField, validate: { max: 50 } }; const data = { - component: 55, + component: 55, }; const context = generateProcessorContext(component, data); const result = await validateMaximumValue(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('max'); -}); + }); -it('Validating a number component that contains the max property will return null if the value is equal to the maximum', async () => { + it('Validating a number component that contains the max property will return null if the value is equal to the maximum', async function () { const component = { ...simpleNumberField, validate: { max: 50 } }; const data = { - component: 50, + component: 50, }; const context = generateProcessorContext(component, data); const result = await validateMaximumValue(context); expect(result).to.equal(null); + }); }); diff --git a/src/process/validation/rules/__tests__/validateMaximumWords.test.ts b/src/process/validation/rules/__tests__/validateMaximumWords.test.ts index 257ee25d..9d93b4d2 100644 --- a/src/process/validation/rules/__tests__/validateMaximumWords.test.ts +++ b/src/process/validation/rules/__tests__/validateMaximumWords.test.ts @@ -5,43 +5,45 @@ import { simpleTextField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateMaximumWords } from '../validateMaximumWords'; -it('Validating a component without the maxWords property will return null', async () => { +describe('validateMaximumWords', function () { + it('Validating a component without the maxWords property will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMaximumWords(context); expect(result).to.equal(null); -}); + }); -it('Validating a component with the maxWords property will return a FieldError if the number of words is greater than the maximum', async () => { + it('Validating a component with the maxWords property will return a FieldError if the number of words is greater than the maximum', async function () { const component = { ...simpleTextField, validate: { maxWords: 3 } }; const data = { - component: "Hello, world, it's me!", + component: "Hello, world, it's me!", }; const context = generateProcessorContext(component, data); const result = await validateMaximumWords(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('maxWords'); -}); + }); -it('Validating a component with the maxWords property will return null if the number of words is equal to the maximum', async () => { + it('Validating a component with the maxWords property will return null if the number of words is equal to the maximum', async function () { const component = { ...simpleTextField, validate: { maxWords: 3 } }; const data = { - component: 'Hello, world, again!', + component: 'Hello, world, again!', }; const context = generateProcessorContext(component, data); const result = await validateMaximumWords(context); expect(result).to.equal(null); -}); + }); -it('Validating a component with the maxWords property will return null if the number of words is less than the maximum', async () => { + it('Validating a component with the maxWords property will return null if the number of words is less than the maximum', async function () { const component = { ...simpleTextField, validate: { maxWords: 3 } }; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMaximumWords(context); expect(result).to.equal(null); + }); }); diff --git a/src/process/validation/rules/__tests__/validateMaximumYear.test.ts b/src/process/validation/rules/__tests__/validateMaximumYear.test.ts index c03d19ed..14c2b0de 100644 --- a/src/process/validation/rules/__tests__/validateMaximumYear.test.ts +++ b/src/process/validation/rules/__tests__/validateMaximumYear.test.ts @@ -6,74 +6,76 @@ import { simpleDayField, simpleTextField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateMaximumYear } from '../validateMaximumYear'; -it('Validating a component without the maxYear parameter will return null', async () => { +describe('validateMaximumYear', function () { + it('Validating a component without the maxYear parameter will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMaximumYear(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component without the maxYear parameter will return null', async () => { + it('Validating a day component without the maxYear parameter will return null', async function () { const component = simpleDayField; const data = { - component: '01/22/2023', + component: '01/22/2023', }; const context = generateProcessorContext(component, data); const result = await validateMaximumYear(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with the maxYear parameter will return a FieldError if the year is greater than the maximum', async () => { + it('Validating a day component with the maxYear parameter will return a FieldError if the year is greater than the maximum', async function () { const component: DayComponent = { - ...simpleDayField, - fields: { - ...simpleDayField.fields, - year: { ...simpleDayField.fields.year, maxYear: '2022' }, - }, - maxYear: '2022', + ...simpleDayField, + fields: { + ...simpleDayField.fields, + year: { ...simpleDayField.fields.year, maxYear: '2022' }, + }, + maxYear: '2022', }; const data = { - component: '01/22/2023', + component: '01/22/2023', }; const context = generateProcessorContext(component, data); const result = await validateMaximumYear(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('maxYear'); -}); + }); -it('Validating a day component with the maxYear parameter will return null if the year is equal to the maximum', async () => { + it('Validating a day component with the maxYear parameter will return null if the year is equal to the maximum', async function () { const component: DayComponent = { - ...simpleDayField, - fields: { - ...simpleDayField.fields, - year: { ...simpleDayField.fields.year, maxYear: '2022' }, - }, - maxYear: '2022', + ...simpleDayField, + fields: { + ...simpleDayField.fields, + year: { ...simpleDayField.fields.year, maxYear: '2022' }, + }, + maxYear: '2022', }; const data = { - component: '01/22/2022', + component: '01/22/2022', }; const context = generateProcessorContext(component, data); const result = await validateMaximumYear(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with the maxYear parameter will return null if the year is less than the maximum', async () => { + it('Validating a day component with the maxYear parameter will return null if the year is less than the maximum', async function () { const component: DayComponent = { - ...simpleDayField, - fields: { - ...simpleDayField.fields, - year: { ...simpleDayField.fields.year, maxYear: '2022' }, - }, - maxYear: '2022', + ...simpleDayField, + fields: { + ...simpleDayField.fields, + year: { ...simpleDayField.fields.year, maxYear: '2022' }, + }, + maxYear: '2022', }; const data = { - component: '01/22/2021', + component: '01/22/2021', }; const context = generateProcessorContext(component, data); const result = await validateMaximumYear(context); expect(result).to.equal(null); + }); }); diff --git a/src/process/validation/rules/__tests__/validateMinimumDay.test.ts b/src/process/validation/rules/__tests__/validateMinimumDay.test.ts index a7ae2878..046f8469 100644 --- a/src/process/validation/rules/__tests__/validateMinimumDay.test.ts +++ b/src/process/validation/rules/__tests__/validateMinimumDay.test.ts @@ -5,54 +5,56 @@ import { simpleDayField, simpleTextField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateMinimumDay } from '../validateMinimumDay'; -it('Validating a non-day component will return null', async () => { +describe('validateMinimumDay', function () { + it('Validating a non-day component will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMinimumDay(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with a day before the minimum day will return a FieldError', async () => { + it('Validating a day component with a day before the minimum day will return a FieldError', async function () { const component = { ...simpleDayField, minDate: '2023-04-01' }; const data = { - component: '03/23/2023', + component: '03/23/2023', }; const context = generateProcessorContext(component, data); const result = await validateMinimumDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('minDay'); -}); + }); -it('Validating a day component with a day after the minimum day will return null', async () => { + it('Validating a day component with a day after the minimum day will return null', async function () { const component = { ...simpleDayField, minDate: '2023-04-01' }; const data = { - component: '04/02/2023', + component: '04/02/2023', }; const context = generateProcessorContext(component, data); const result = await validateMinimumDay(context); expect(result).to.equal(null); -}); + }); -it('Validating a day-first day component with a day before the minimum day will return a FieldError', async () => { + it('Validating a day-first day component with a day before the minimum day will return a FieldError', async function () { const component = { ...simpleDayField, dayFirst: true, minDate: '2023-04-01' }; const data = { - component: '02/02/2023', + component: '02/02/2023', }; const context = generateProcessorContext(component, data); const result = await validateMinimumDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.contain('minDay'); -}); + }); -it('Validating a day-first day component with a day after the minimum day will return null', async () => { + it('Validating a day-first day component with a day after the minimum day will return null', async function () { const component = { ...simpleDayField, dayFirst: true, minDate: '2023-04-01' }; const data = { - component: '23/04/2023', + component: '23/04/2023', }; const context = generateProcessorContext(component, data); const result = await validateMinimumDay(context); expect(result).to.equal(null); + }); }); diff --git a/src/process/validation/rules/__tests__/validateMinimumLength.test.ts b/src/process/validation/rules/__tests__/validateMinimumLength.test.ts index 1308d5fc..0f0d229c 100644 --- a/src/process/validation/rules/__tests__/validateMinimumLength.test.ts +++ b/src/process/validation/rules/__tests__/validateMinimumLength.test.ts @@ -5,43 +5,45 @@ import { simpleTextField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateMinimumLength } from '../validateMinimumLength'; -it('Validating a component without a minLength property will return null', async () => { +describe('validateMinimumLength', function () { + it('Validating a component without a minLength property will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMinimumLength(context); expect(result).to.equal(null); -}); + }); -it('Validating a component with a minLength property and a length less than minLength will return a FieldError', async () => { + it('Validating a component with a minLength property and a length less than minLength will return a FieldError', async function () { const component = { ...simpleTextField, validate: { minLength: 4 } }; const data = { - component: 'foo', + component: 'foo', }; const context = generateProcessorContext(component, data); const result = await validateMinimumLength(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('minLength'); -}); + }); -it('Validating a component with a minLength property and a length equal to minLength will return null', async () => { + it('Validating a component with a minLength property and a length equal to minLength will return null', async function () { const component = { ...simpleTextField, validate: { minLength: 4 } }; const data = { - component: 'fooo', + component: 'fooo', }; const context = generateProcessorContext(component, data); const result = await validateMinimumLength(context); expect(result).to.equal(null); -}); + }); -it('Validating a component with a minLength property and a length greater than minLength will return null', async () => { + it('Validating a component with a minLength property and a length greater than minLength will return null', async function () { const component = { ...simpleTextField, validate: { minLength: 4 } }; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMinimumLength(context); expect(result).to.equal(null); + }); }); diff --git a/src/process/validation/rules/__tests__/validateMinimumSelectedCount.test.ts b/src/process/validation/rules/__tests__/validateMinimumSelectedCount.test.ts index 4bc0ed5f..722190f4 100644 --- a/src/process/validation/rules/__tests__/validateMinimumSelectedCount.test.ts +++ b/src/process/validation/rules/__tests__/validateMinimumSelectedCount.test.ts @@ -5,73 +5,75 @@ import { simpleSelectBoxes, simpleTextField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateMinimumSelectedCount } from '../validateMinimumSelectedCount'; -it('Validting a non-select boxes component will return null', async () => { +describe('validateMinimumSelectedCount', function () { + it('Validting a non-select boxes component will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMinimumSelectedCount(context); expect(result).to.equal(null); -}); + }); -it('Validating a select boxes component without minSelectedCount will return null', async () => { + it('Validating a select boxes component without minSelectedCount will return null', async function () { const component = simpleSelectBoxes; const data = { - component: { - foo: true, - bar: true, - baz: false, - biz: false, - }, + component: { + foo: true, + bar: true, + baz: false, + biz: false, + }, }; const context = generateProcessorContext(component, data); const result = await validateMinimumSelectedCount(context); expect(result).to.equal(null); -}); + }); -it('Validating a select boxes component where the number of selected fields is less than minSelectedCount will return a FieldError', async () => { + it('Validating a select boxes component where the number of selected fields is less than minSelectedCount will return a FieldError', async function () { const component = { ...simpleSelectBoxes, validate: { minSelectedCount: 2 } }; const data = { - component: { - foo: true, - bar: false, - baz: false, - biz: false, - }, + component: { + foo: true, + bar: false, + baz: false, + biz: false, + }, }; const context = generateProcessorContext(component, data); const result = await validateMinimumSelectedCount(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.contain('minSelectedCount'); -}); + }); -it('Validating a select boxes component where the number of selected fields is equal to minSelectedCount will return null', async () => { + it('Validating a select boxes component where the number of selected fields is equal to minSelectedCount will return null', async function () { const component = { ...simpleSelectBoxes, validate: { minSelectedCount: 2 } }; const data = { - component: { - foo: true, - bar: true, - baz: false, - biz: false, - }, + component: { + foo: true, + bar: true, + baz: false, + biz: false, + }, }; const context = generateProcessorContext(component, data); const result = await validateMinimumSelectedCount(context); expect(result).to.equal(null); -}); + }); -it('Validating a select boxes component where the number of selected fields is greater than minSelectedCount will return null', async () => { + it('Validating a select boxes component where the number of selected fields is greater than minSelectedCount will return null', async function () { const component = { ...simpleSelectBoxes, validate: { minSelectedCount: 2 } }; const data = { - component: { - foo: true, - bar: true, - baz: true, - biz: false, - }, + component: { + foo: true, + bar: true, + baz: true, + biz: false, + }, }; const context = generateProcessorContext(component, data); const result = await validateMinimumSelectedCount(context); expect(result).to.equal(null); + }); }); diff --git a/src/process/validation/rules/__tests__/validateMinimumValue.test.ts b/src/process/validation/rules/__tests__/validateMinimumValue.test.ts index 791bd302..dd0facaf 100644 --- a/src/process/validation/rules/__tests__/validateMinimumValue.test.ts +++ b/src/process/validation/rules/__tests__/validateMinimumValue.test.ts @@ -5,53 +5,55 @@ import { simpleNumberField, simpleTextField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateMinimumValue } from '../validateMinimumValue'; -it('Validating a component without the min property will return null', async () => { +describe('validateMinimumValue', function () { + it('Validating a component without the min property will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMinimumValue(context); expect(result).to.equal(null); -}); + }); -it('Validating a number component without the min property will return null', async () => { + it('Validating a number component without the min property will return null', async function () { const component = simpleNumberField; const data = { - component: 3, + component: 3, }; const context = generateProcessorContext(component, data); const result = await validateMinimumValue(context); expect(result).to.equal(null); -}); + }); -it('Validating a number component that contains the min property will return null if the value is greater than the minimum', async () => { + it('Validating a number component that contains the min property will return null if the value is greater than the minimum', async function () { const component = { ...simpleNumberField, validate: { min: 50 } }; const data = { - component: 55, + component: 55, }; const context = generateProcessorContext(component, data); const result = await validateMinimumValue(context); expect(result).to.equal(null); -}); + }); -it('Validating a number component that contains the min property will return a FieldError if the value is less than the minimum', async () => { + it('Validating a number component that contains the min property will return a FieldError if the value is less than the minimum', async function () { const component = { ...simpleNumberField, validate: { min: 50 } }; const data = { - component: 35, + component: 35, }; const context = generateProcessorContext(component, data); const result = await validateMinimumValue(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.contain('min'); -}); + }); -it('Validating a number component that contains the min property will return null if the value is equal to the minimum', async () => { + it('Validating a number component that contains the min property will return null if the value is equal to the minimum', async function () { const component = { ...simpleNumberField, validate: { min: 50 } }; const data = { - component: 50, + component: 50, }; const context = generateProcessorContext(component, data); const result = await validateMinimumValue(context); expect(result).to.equal(null); + }); }); diff --git a/src/process/validation/rules/__tests__/validateMinimumWords.test.ts b/src/process/validation/rules/__tests__/validateMinimumWords.test.ts index ce6fd2d8..e24eef32 100644 --- a/src/process/validation/rules/__tests__/validateMinimumWords.test.ts +++ b/src/process/validation/rules/__tests__/validateMinimumWords.test.ts @@ -5,43 +5,45 @@ import { simpleTextField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateMinimumWords } from '../validateMinimumWords'; -it('Validating a component without the maxWords property will return null', async () => { +describe('validateMinimumWords', function () { + it('Validating a component without the maxWords property will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMinimumWords(context); expect(result).to.equal(null); -}); + }); -it('Validating a component with the minWords property will return a FieldError if the number of words is less than the minimum', async () => { + it('Validating a component with the minWords property will return a FieldError if the number of words is less than the minimum', async function () { const component = { ...simpleTextField, validate: { minWords: 3 } }; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateMinimumWords(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('minWords'); -}); + }); -it('Validating a component with the minWords property will return null if the number of words is equal to the minimum', async () => { + it('Validating a component with the minWords property will return null if the number of words is equal to the minimum', async function () { const component = { ...simpleTextField, validate: { minWords: 3 } }; const data = { - component: 'Hello, world, again!', + component: 'Hello, world, again!', }; const context = generateProcessorContext(component, data); const result = await validateMinimumWords(context); expect(result).to.equal(null); -}); + }); -it('Validating a component with the minWords property will return null if the number of words is greater than the minimum', async () => { + it('Validating a component with the minWords property will return null if the number of words is greater than the minimum', async function () { const component = { ...simpleTextField, validate: { minWords: 3 } }; const data = { - component: 'Hello, world, it is I!', + component: 'Hello, world, it is I!', }; const context = generateProcessorContext(component, data); const result = await validateMinimumWords(context); expect(result).to.equal(null); + }); }); diff --git a/src/process/validation/rules/__tests__/validateMinimumYear.test.ts b/src/process/validation/rules/__tests__/validateMinimumYear.test.ts index 10dc272b..5ba81354 100644 --- a/src/process/validation/rules/__tests__/validateMinimumYear.test.ts +++ b/src/process/validation/rules/__tests__/validateMinimumYear.test.ts @@ -6,74 +6,76 @@ import { simpleDayField, simpleTextField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateMinimumYear } from '../validateMinimumYear'; -it('Validating a component without the minYear parameter will return null', async () => { +describe('validateMinimumYear', function () { + it('Validating a component without the minYear parameter will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', - } + component: 'Hello, world!', + }; const context = generateProcessorContext(component, data); const result = await validateMinimumYear(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component without the minYear parameter will return null', async () => { + it('Validating a day component without the minYear parameter will return null', async function () { const component = simpleDayField; const data = { - component: '01/22/2023', + component: '01/22/2023', }; const context = generateProcessorContext(component, data); const result = await validateMinimumYear(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with the minYear parameter will return a FieldError if the year is less than the minimum', async () => { + it('Validating a day component with the minYear parameter will return a FieldError if the year is less than the minimum', async function () { const component: DayComponent = { - ...simpleDayField, - fields: { - ...simpleDayField.fields, - year: { ...simpleDayField.fields.year, minYear: '2023' }, - }, - minYear: '2023', + ...simpleDayField, + fields: { + ...simpleDayField.fields, + year: { ...simpleDayField.fields.year, minYear: '2023' }, + }, + minYear: '2023', }; const data = { - component: '01/22/2022', + component: '01/22/2022', }; const context = generateProcessorContext(component, data); const result = await validateMinimumYear(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.contain('minYear'); -}); + }); -it('Validating a day component with the minYear parameter will return null if the year is equal to the minimum', async () => { + it('Validating a day component with the minYear parameter will return null if the year is equal to the minimum', async function () { const component: DayComponent = { - ...simpleDayField, - fields: { - ...simpleDayField.fields, - year: { ...simpleDayField.fields.year, minYear: '2022' }, - }, - minYear: '2022', + ...simpleDayField, + fields: { + ...simpleDayField.fields, + year: { ...simpleDayField.fields.year, minYear: '2022' }, + }, + minYear: '2022', }; const data = { - component: '01/22/2022', + component: '01/22/2022', }; const context = generateProcessorContext(component, data); const result = await validateMinimumYear(context); expect(result).to.equal(null); -}); + }); -it('Validating a day component with the minYear parameter will return null if the year is greater than the minimum', async () => { + it('Validating a day component with the minYear parameter will return null if the year is greater than the minimum', async function () { const component: DayComponent = { - ...simpleDayField, - fields: { - ...simpleDayField.fields, - year: { ...simpleDayField.fields.year, minYear: '2022' }, - }, - minYear: '2022', + ...simpleDayField, + fields: { + ...simpleDayField.fields, + year: { ...simpleDayField.fields.year, minYear: '2022' }, + }, + minYear: '2022', }; const data = { - component: '01/22/2023', + component: '01/22/2023', }; const context = generateProcessorContext(component, data); const result = await validateMinimumYear(context); expect(result).to.equal(null); + }); }); diff --git a/src/process/validation/rules/__tests__/validateMultiple.test.ts b/src/process/validation/rules/__tests__/validateMultiple.test.ts index c698ef3c..b3281902 100644 --- a/src/process/validation/rules/__tests__/validateMultiple.test.ts +++ b/src/process/validation/rules/__tests__/validateMultiple.test.ts @@ -4,444 +4,444 @@ import { expect } from 'chai'; import { isEligible, emptyValueIsArray, validateMultipleSync } from '../validateMultiple'; import { FieldError } from 'error'; -describe('validateMultiple', () => { - describe('isEligible', () => { - it('should return false for hidden component with multiple', () => { - const component: Component = { - type: 'hidden', - input: true, - key: 'hidden', - }; - expect(isEligible(component)).to.be.false; - }); +describe('validateMultiple', function () { + describe('isEligible', function () { + it('should return false for hidden component with multiple', function () { + const component: Component = { + type: 'hidden', + input: true, + key: 'hidden', + }; + expect(isEligible(component)).to.equal(false); + }); - it('should return false for address component if not multiple', () => { - const component: Component = { - type: 'address', - input: true, - key: 'address', - }; - expect(isEligible(component)).to.be.false; - }); + it('should return false for address component if not multiple', function () { + const component: Component = { + type: 'address', + input: true, + key: 'address', + }; + expect(isEligible(component)).to.equal(false); + }); - it('should return true for address component if multiple', () => { - const component: Component = { - type: 'address', - input: true, - key: 'address', - multiple: true, - }; - expect(isEligible(component)).to.be.true; - }); + it('should return true for address component if multiple', function () { + const component: Component = { + type: 'address', + input: true, + key: 'address', + multiple: true, + }; + expect(isEligible(component)).to.equal(true); + }); - it('should return false for textArea component with as !== json if multiple', () => { - const component: TextAreaComponent = { - type: 'textarea', - as: 'text', - input: true, - key: 'textArea', - multiple: true, - rows: 4, - wysiwyg: true, - editor: 'ckeditor', - fixedSize: true, - inputFormat: 'plain', - }; - expect(isEligible(component)).to.be.false; - }); + it('should return false for textArea component with as !== json if multiple', function () { + const component: TextAreaComponent = { + type: 'textarea', + as: 'text', + input: true, + key: 'textArea', + multiple: true, + rows: 4, + wysiwyg: true, + editor: 'ckeditor', + fixedSize: true, + inputFormat: 'plain', + }; + expect(isEligible(component)).to.equal(false); + }); - it('should return true for textArea component with as === json if multiple', () => { - const component: TextAreaComponent = { - type: 'textarea', - as: 'json', - input: true, - key: 'textAreaJson', - multiple: true, - rows: 4, - wysiwyg: true, - editor: 'ckeditor', - fixedSize: true, - inputFormat: 'plain', - }; - expect(isEligible(component)).to.be.true; - }); + it('should return true for textArea component with as === json if multiple', function () { + const component: TextAreaComponent = { + type: 'textarea', + as: 'json', + input: true, + key: 'textAreaJson', + multiple: true, + rows: 4, + wysiwyg: true, + editor: 'ckeditor', + fixedSize: true, + inputFormat: 'plain', + }; + expect(isEligible(component)).to.equal(true); + }); - it('should return false for textArea component with as === json if not multiple', () => { - const component: TextAreaComponent = { - type: 'textarea', - as: 'json', - input: true, - key: 'textAreaJson', - rows: 4, - wysiwyg: true, - editor: 'ace', - fixedSize: true, - inputFormat: 'plain', - }; - expect(isEligible(component)).to.be.false; - }); + it('should return false for textArea component with as === json if not multiple', function () { + const component: TextAreaComponent = { + type: 'textarea', + as: 'json', + input: true, + key: 'textAreaJson', + rows: 4, + wysiwyg: true, + editor: 'ace', + fixedSize: true, + inputFormat: 'plain', + }; + expect(isEligible(component)).to.equal(false); + }); - it('should return true for other component types', () => { - const component: Component = { - type: 'textfield', - input: true, - key: 'textfield', - multiple: true, - }; - expect(isEligible(component)).to.be.true; - }); + it('should return true for other component types', function () { + const component: Component = { + type: 'textfield', + input: true, + key: 'textfield', + multiple: true, + }; + expect(isEligible(component)).to.equal(true); }); + }); - describe('emptyValueIsArray', () => { - it('should return true for datagrid component', () => { - const component: Component = { - type: 'datagrid', - input: true, - key: 'datagrid', - }; - expect(emptyValueIsArray(component)).to.be.true; - }); + describe('emptyValueIsArray', function () { + it('should return true for datagrid component', function () { + const component: Component = { + type: 'datagrid', + input: true, + key: 'datagrid', + }; + expect(emptyValueIsArray(component)).to.equal(true); + }); - it('should return true for editgrid component', () => { - const component: Component = { - type: 'editgrid', - input: true, - key: 'editgrid', - }; - expect(emptyValueIsArray(component)).to.be.true; - }); + it('should return true for editgrid component', function () { + const component: Component = { + type: 'editgrid', + input: true, + key: 'editgrid', + }; + expect(emptyValueIsArray(component)).to.equal(true); + }); - it('should return true for tagpad component', () => { - const component: Component = { - type: 'tagpad', - input: true, - key: 'tagpad', - }; - expect(emptyValueIsArray(component)).to.be.true; - }); + it('should return true for tagpad component', function () { + const component: Component = { + type: 'tagpad', + input: true, + key: 'tagpad', + }; + expect(emptyValueIsArray(component)).to.equal(true); + }); - it('should return true for sketchpad component', () => { - const component: Component = { - type: 'sketchpad', - input: true, - key: 'sketchpad', - }; - expect(emptyValueIsArray(component)).to.be.true; - }); + it('should return true for sketchpad component', function () { + const component: Component = { + type: 'sketchpad', + input: true, + key: 'sketchpad', + }; + expect(emptyValueIsArray(component)).to.equal(true); + }); - it('should return true for datatable component', () => { - const component: Component = { - type: 'datatable', - input: true, - key: 'datatable', - }; - expect(emptyValueIsArray(component)).to.be.true; - }); + it('should return true for datatable component', function () { + const component: Component = { + type: 'datatable', + input: true, + key: 'datatable', + }; + expect(emptyValueIsArray(component)).to.equal(true); + }); - it('should return true for dynamicWizard component', () => { - const component: Component = { - type: 'dynamicWizard', - input: true, - key: 'dynamicWizard', - }; - expect(emptyValueIsArray(component)).to.be.true; - }); + it('should return true for dynamicWizard component', function () { + const component: Component = { + type: 'dynamicWizard', + input: true, + key: 'dynamicWizard', + }; + expect(emptyValueIsArray(component)).to.equal(true); + }); - it('should return true for file component', () => { - const component: Component = { - type: 'file', - input: true, - key: 'file', - }; - expect(emptyValueIsArray(component)).to.be.true; - }); + it('should return true for file component', function () { + const component: Component = { + type: 'file', + input: true, + key: 'file', + }; + expect(emptyValueIsArray(component)).to.equal(true); + }); - it('should return false for select component without multiple', () => { - const component: Component = { - type: 'select', - input: true, - key: 'select', - }; - expect(emptyValueIsArray(component)).to.be.false; - }); + it('should return false for select component without multiple', function () { + const component: Component = { + type: 'select', + input: true, + key: 'select', + }; + expect(emptyValueIsArray(component)).to.equal(false); + }); - it('should return true for select component with multiple', () => { - const component: Component = { - type: 'select', - input: true, - key: 'select', - multiple: true, - }; - expect(emptyValueIsArray(component)).to.be.true; - }); + it('should return true for select component with multiple', function () { + const component: Component = { + type: 'select', + input: true, + key: 'select', + multiple: true, + }; + expect(emptyValueIsArray(component)).to.equal(true); + }); - it('should return true for tags component with storeas !== string', () => { - const component: Component = { - type: 'tags', - input: true, - key: 'tags', - storeas: 'array', - }; - expect(emptyValueIsArray(component)).to.be.true; - }); + it('should return true for tags component with storeas !== string', function () { + const component: Component = { + type: 'tags', + input: true, + key: 'tags', + storeas: 'array', + }; + expect(emptyValueIsArray(component)).to.equal(true); + }); - it('should return false for tags component with storeas === string', () => { - const component: Component = { - type: 'tags', - input: true, - key: 'tags', - storeas: 'string', - }; - expect(emptyValueIsArray(component)).to.be.false; - }); + it('should return false for tags component with storeas === string', function () { + const component: Component = { + type: 'tags', + input: true, + key: 'tags', + storeas: 'string', + }; + expect(emptyValueIsArray(component)).to.equal(false); + }); - it('should return false for other component types', () => { - const component: Component = { - type: 'textfield', - input: true, - key: 'textfield', - }; - expect(emptyValueIsArray(component)).to.be.false; - }); + it('should return false for other component types', function () { + const component: Component = { + type: 'textfield', + input: true, + key: 'textfield', + }; + expect(emptyValueIsArray(component)).to.equal(false); }); + }); - describe('validateMultipleSync', () => { - describe('values that should be arrays', () => { - // TODO: skipping the following tests until we can resolve whether or not we want to validateMultiple on select components - xit('should return an error for a select component with multiple that is not an array', () => { - const component: Component = { - type: 'select', - input: true, - key: 'select', - multiple: true, - }; - const context: ValidationContext = { - component, - data: { - select: 'foo', - }, - value: 'foo', - row: { - select: 'foo' - }, - scope: { - errors: [] - }, - path: component.key, - }; - expect(validateMultipleSync(context)).to.be.instanceOf(FieldError); - }); + describe('validateMultipleSync', function () { + describe('values that should be arrays', function () { + // TODO: skipping the following tests until we can resolve whether or not we want to validateMultiple on select components + xit('should return an error for a select component with multiple that is not an array', function () { + const component: Component = { + type: 'select', + input: true, + key: 'select', + multiple: true, + }; + const context: ValidationContext = { + component, + data: { + select: 'foo', + }, + value: 'foo', + row: { + select: 'foo', + }, + scope: { + errors: [], + }, + path: component.key, + }; + expect(validateMultipleSync(context)).to.be.instanceOf(FieldError); + }); - xit('should return null for a select component with multiple that is an array', () => { - const component: Component = { - type: 'select', - input: true, - key: 'select', - multiple: true, - }; - const context: ValidationContext = { - component, - data: { - select: ['foo'], - }, - value: ['foo'], - row: { - select: 'foo' - }, - scope: { - errors: [] - }, - path: component.key, - }; - expect(validateMultipleSync(context)).to.be.null; - }); + xit('should return null for a select component with multiple that is an array', function () { + const component: Component = { + type: 'select', + input: true, + key: 'select', + multiple: true, + }; + const context: ValidationContext = { + component, + data: { + select: ['foo'], + }, + value: ['foo'], + row: { + select: 'foo', + }, + scope: { + errors: [], + }, + path: component.key, + }; + expect(validateMultipleSync(context)).to.equal(null); + }); - xit('should return an error for a select component without multiple that is an array', () => { - const component: Component = { - type: 'select', - input: true, - key: 'select', - }; - const context: ValidationContext = { - component, - data: { - select: ['foo'], - }, - value: ['foo'], - row: { - select: ['foo'] - }, - scope: { - errors: [] - }, - path: component.key, - }; - expect(validateMultipleSync(context)).to.be.instanceOf(FieldError); - }); + xit('should return an error for a select component without multiple that is an array', function () { + const component: Component = { + type: 'select', + input: true, + key: 'select', + }; + const context: ValidationContext = { + component, + data: { + select: ['foo'], + }, + value: ['foo'], + row: { + select: ['foo'], + }, + scope: { + errors: [], + }, + path: component.key, + }; + expect(validateMultipleSync(context)).to.be.instanceOf(FieldError); + }); - xit('should return null for a select component without multiple that is not an array', () => { - const component: Component = { - type: 'select', - input: true, - key: 'select', - }; - const context: ValidationContext = { - component, - data: { - select: 'foo', - }, - value: 'foo', - row: { - select: 'foo' - }, - scope: { - errors: [] - }, - path: component.key, - }; - expect(validateMultipleSync(context)).to.be.null; - }); + xit('should return null for a select component without multiple that is not an array', function () { + const component: Component = { + type: 'select', + input: true, + key: 'select', + }; + const context: ValidationContext = { + component, + data: { + select: 'foo', + }, + value: 'foo', + row: { + select: 'foo', + }, + scope: { + errors: [], + }, + path: component.key, + }; + expect(validateMultipleSync(context)).to.equal(null); + }); - it('should not validate a select component with multiple', () => { - const component: Component = { - type: 'select', - input: true, - key: 'select', - multiple: true, - }; - const context: ValidationContext = { - component, - data: { - select: ['foo', 'bar'], - }, - value: ['foo', 'bar'], - row: { - select: ['foo', 'bar'], - }, - scope: { - errors: [] - }, - path: component.key, - }; - expect(validateMultipleSync(context)).to.be.null; - }); + it('should not validate a select component with multiple', function () { + const component: Component = { + type: 'select', + input: true, + key: 'select', + multiple: true, + }; + const context: ValidationContext = { + component, + data: { + select: ['foo', 'bar'], + }, + value: ['foo', 'bar'], + row: { + select: ['foo', 'bar'], + }, + scope: { + errors: [], + }, + path: component.key, + }; + expect(validateMultipleSync(context)).to.equal(null); + }); - it('should return null for a sketchpad component', () => { - const component: Component = { - type: 'sketchpad', - input: true, - key: 'sketchpad', - }; - const context: ValidationContext = { - component, - data: { - sketchpad: ['foo'], - }, - value: ['foo'], - row: { - sketchpad: ['foo'] - }, - scope: { - errors: [] - }, - path: component.key, - }; - expect(validateMultipleSync(context)).to.be.null; - }); + it('should return null for a sketchpad component', function () { + const component: Component = { + type: 'sketchpad', + input: true, + key: 'sketchpad', + }; + const context: ValidationContext = { + component, + data: { + sketchpad: ['foo'], + }, + value: ['foo'], + row: { + sketchpad: ['foo'], + }, + scope: { + errors: [], + }, + path: component.key, + }; + expect(validateMultipleSync(context)).to.equal(null); + }); - it('should return null for a tagpad component', () => { - const component: Component = { - type: 'sketchpad', - input: true, - key: 'tagpad', - }; - const context: ValidationContext = { - component, - data: { - tagpad: ['foo'], - }, - value: ['foo'], - row: { - tagpad: ['foo'] - }, - scope: { - errors: [] - }, - path: component.key, - }; - expect(validateMultipleSync(context)).to.be.null; - }); + it('should return null for a tagpad component', function () { + const component: Component = { + type: 'sketchpad', + input: true, + key: 'tagpad', + }; + const context: ValidationContext = { + component, + data: { + tagpad: ['foo'], + }, + value: ['foo'], + row: { + tagpad: ['foo'], + }, + scope: { + errors: [], + }, + path: component.key, + }; + expect(validateMultipleSync(context)).to.equal(null); + }); - it('should return null for a data table component', () => { - const component: Component = { - type: 'datatable', - input: true, - key: 'datatable', - }; - const context: ValidationContext = { - component, - data: { - [component.key]: ['foo'], - }, - value: ['foo'], - row: { - [component.key]: ['foo'] - }, - scope: { - errors: [] - }, - path: component.key, - }; - expect(validateMultipleSync(context)).to.be.null; - }); + it('should return null for a data table component', function () { + const component: Component = { + type: 'datatable', + input: true, + key: 'datatable', + }; + const context: ValidationContext = { + component, + data: { + [component.key]: ['foo'], + }, + value: ['foo'], + row: { + [component.key]: ['foo'], + }, + scope: { + errors: [], + }, + path: component.key, + }; + expect(validateMultipleSync(context)).to.equal(null); + }); - it('should return null for a dynamic wizard component', () => { - const component: Component = { - type: 'dynamicWizard', - input: true, - key: 'dynamicwizard', - }; - const context: ValidationContext = { - component, - data: { - [component.key]: ['foo'], - }, - value: ['foo'], - row: { - [component.key]: ['foo'] - }, - scope: { - errors: [] - }, - path: component.key, - }; - expect(validateMultipleSync(context)).to.be.null; - }); - }); + it('should return null for a dynamic wizard component', function () { + const component: Component = { + type: 'dynamicWizard', + input: true, + key: 'dynamicwizard', + }; + const context: ValidationContext = { + component, + data: { + [component.key]: ['foo'], + }, + value: ['foo'], + row: { + [component.key]: ['foo'], + }, + scope: { + errors: [], + }, + path: component.key, + }; + expect(validateMultipleSync(context)).to.equal(null); + }); + }); - describe('values that should not be arrays', () => { - it('should return an error for a textfield component without multiple that is an array', () => { - const component: Component = { - type: 'textfield', - input: true, - key: 'textfield', - }; - const context: ValidationContext = { - component, - data: { - textfield: ['foo'], - }, - value: ['foo'], - row: { - textfield: ['foo'] - }, - scope: { - errors: [] - }, - path: component.key, - }; - expect(validateMultipleSync(context)).to.be.instanceOf(FieldError); - }); - }); + describe('values that should not be arrays', function () { + it('should return an error for a textfield component without multiple that is an array', function () { + const component: Component = { + type: 'textfield', + input: true, + key: 'textfield', + }; + const context: ValidationContext = { + component, + data: { + textfield: ['foo'], + }, + value: ['foo'], + row: { + textfield: ['foo'], + }, + scope: { + errors: [], + }, + path: component.key, + }; + expect(validateMultipleSync(context)).to.be.instanceOf(FieldError); + }); }); + }); }); diff --git a/src/process/validation/rules/__tests__/validateNumber.test.ts b/src/process/validation/rules/__tests__/validateNumber.test.ts index 05b8ddef..76ef6ca4 100644 --- a/src/process/validation/rules/__tests__/validateNumber.test.ts +++ b/src/process/validation/rules/__tests__/validateNumber.test.ts @@ -6,49 +6,51 @@ import { generateProcessorContext } from './fixtures/util'; import { validateNumber } from '../validateNumber'; import { validateMultiple } from '../validateMultiple'; -it('Validating a valid number will return null', async () => { +describe('validateNumber', function () { + it('Validating a valid number will return null', async function () { const component = simpleNumberField; const data = { - component: 45, + component: 45, }; const context = generateProcessorContext(component, data); const result = await validateNumber(context); expect(result).to.equal(null); -}); + }); -it('Validating an invalid number will return a FieldError', async () => { + it('Validating an invalid number will return a FieldError', async function () { const component = simpleNumberField; const data = { - component: 'text', + component: 'text', }; const context = generateProcessorContext(component, data); const result = await validateNumber(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.contain('number'); -}); + }); -it('Validating a multiple number with a blank value will return null', async () => { + it('Validating a multiple number with a blank value will return null', async function () { const component = { - ...simpleNumberField, - multiple: true + ...simpleNumberField, + multiple: true, }; const data = { - component: [null], + component: [null], }; const context = generateProcessorContext(component, data); const result = await validateMultiple(context); expect(result).to.equal(null); -}); + }); -it('Validating a multiple number with an empty array value will return null', async () => { + it('Validating a multiple number with an empty array value will return null', async function () { const component = { - ...simpleNumberField, - multiple: true + ...simpleNumberField, + multiple: true, }; const data = { - component: [], + component: [], }; const context = generateProcessorContext(component, data); const result = await validateMultiple(context); expect(result).to.equal(null); + }); }); diff --git a/src/process/validation/rules/__tests__/validateRegexPattern.test.ts b/src/process/validation/rules/__tests__/validateRegexPattern.test.ts index c51ff40b..b267ad8f 100644 --- a/src/process/validation/rules/__tests__/validateRegexPattern.test.ts +++ b/src/process/validation/rules/__tests__/validateRegexPattern.test.ts @@ -5,54 +5,60 @@ import { simpleTextField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateRegexPattern } from '../validateRegexPattern'; -it('Validating a component without a pattern parameter will return null', async () => { +describe('validateRegexPattern', function () { + it('Validating a component without a pattern parameter will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateRegexPattern(context); expect(result).to.equal(null); -}); + }); -it('Validating a component with a pattern parameter will return a FieldError if the value does not match the pattern', async () => { + it('Validating a component with a pattern parameter will return a FieldError if the value does not match the pattern', async function () { const component = { ...simpleTextField, validate: { pattern: '\\d*' } }; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); - const result = await validateRegexPattern(context); expect(result).to.be.instanceOf(FieldError); + const result = await validateRegexPattern(context); + expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('pattern'); -}); + }); -it('Validating a component with a pattern parameter will return null if the value matches the pattern', async () => { + it('Validating a component with a pattern parameter will return null if the value matches the pattern', async function () { const component = { ...simpleTextField, validate: { pattern: '\\d*' } }; const data = { - component: '12345', + component: '12345', }; const context = generateProcessorContext(component, data); const result = await validateRegexPattern(context); expect(result).to.equal(null); -}); + }); -it('Validating a component with an empty value will not trigger the pattern validation', async () => { + it('Validating a component with an empty value will not trigger the pattern validation', async function () { const component = { ...simpleTextField, validate: { pattern: '\\d' } }; const data = { - component: '' + component: '', }; const context = generateProcessorContext(component, data); const result = await validateRegexPattern(context); expect(result).to.equal(null); -}); + }); -it('Validating a component with a pattern parameter and a pattern message will return a FieldError if the value does not match the pattern', async () => { - const component = { ...simpleTextField, validate: { pattern: '\\d', patternMessage: 'Can only contain digits.' } }; + it('Validating a component with a pattern parameter and a pattern message will return a FieldError if the value does not match the pattern', async function () { + const component = { + ...simpleTextField, + validate: { pattern: '\\d', patternMessage: 'Can only contain digits.' }, + }; const data = { - component: 'abc', + component: 'abc', }; const context = generateProcessorContext(component, data); const result = await validateRegexPattern(context); expect(result).to.be.instanceOf(FieldError); expect(result).to.have.property('errorKeyOrMessage', 'Can only contain digits.'); + }); }); diff --git a/src/process/validation/rules/__tests__/validateRequired.test.ts b/src/process/validation/rules/__tests__/validateRequired.test.ts index 0ae84619..941de965 100644 --- a/src/process/validation/rules/__tests__/validateRequired.test.ts +++ b/src/process/validation/rules/__tests__/validateRequired.test.ts @@ -3,72 +3,75 @@ import { expect } from 'chai'; import { FieldError } from 'error'; import { validateRequired } from '../validateRequired'; import { - conditionallyHiddenRequiredHiddenField, - hiddenRequiredField, - requiredNonInputField, - simpleTextField, - simpleSelectBoxes, - simpleRadioField, - simpleCheckBoxField, + conditionallyHiddenRequiredHiddenField, + hiddenRequiredField, + requiredNonInputField, + simpleTextField, + simpleSelectBoxes, + simpleRadioField, + simpleCheckBoxField, } from './fixtures/components'; import { processOne } from 'processes/processOne'; import { generateProcessorContext } from './fixtures/util'; import { ProcessorsContext, SelectBoxesComponent, ValidationScope } from 'types'; -import { validateAllProcess, validateProcessInfo } from 'processes/validation'; +import { validateProcessInfo } from 'processes/validation'; -it('Validating a simple component that is required and not present in the data will return a field error', async () => { +describe('validateRequired', function () { + it('Validating a simple component that is required and not present in the data will return a field error', async function () { const component = { ...simpleTextField, validate: { required: true } }; const data = {}; const context = generateProcessorContext(component, data); const result = await validateRequired(context); expect(result).to.be.instanceOf(FieldError); expect(result && result.errorKeyOrMessage).to.equal('required'); -}); + }); -it('Validating a simple component that is required and present in the data will return null', async () => { + it('Validating a simple component that is required and present in the data will return null', async function () { const component = { ...simpleTextField, validate: { required: true } }; const data = { component: 'a simple value' }; const context = generateProcessorContext(component, data); const result = await validateRequired(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple component that is not required and present in the data will return null', async () => { + it('Validating a simple component that is not required and present in the data will return null', async function () { const component = simpleTextField; const data = { component: 'a simple value' }; const context = generateProcessorContext(component, data); const result = await validateRequired(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple component that is not required and not present in the data will return null', async () => { + it('Validating a simple component that is not required and not present in the data will return null', async function () { const component = simpleTextField; const data = {}; const context = generateProcessorContext(component, data); const result = await validateRequired(context); expect(result).to.equal(null); -}); + }); -it('Should validate a hidden component that does not contain data', async () => { + it('Should validate a hidden component that does not contain data', async function () { const component = hiddenRequiredField; - const data = {otherData: 'hideme'}; + const data = { otherData: 'hideme' }; const context = generateProcessorContext(component, data) as ProcessorsContext; context.processors = [validateProcessInfo]; await processOne(context); expect(context.scope.errors.length).to.equal(1); - expect(context.scope.errors[0] && context.scope.errors[0].errorKeyOrMessage).to.equal('required'); -}); + expect(context.scope.errors[0] && context.scope.errors[0].errorKeyOrMessage).to.equal( + 'required', + ); + }); -it('Should not validate a hidden component that is conditionally hidden', async () => { + it('Should not validate a hidden component that is conditionally hidden', async function () { const component = conditionallyHiddenRequiredHiddenField; - const data = {otherData: 'hideme'}; + const data = { otherData: 'hideme' }; const context = generateProcessorContext(component, data) as ProcessorsContext; context.processors = [validateProcessInfo]; await processOne(context); expect(context.scope.errors.length).to.equal(0); -}); + }); -it('Should not validate a hidden component that has the hidden property set to true.', async () => { + it('Should not validate a hidden component that has the hidden property set to true.', async function () { const component = hiddenRequiredField; component.hidden = true; const data = {}; @@ -76,130 +79,146 @@ it('Should not validate a hidden component that has the hidden property set to t context.processors = [validateProcessInfo]; await processOne(context); expect(context.scope.errors.length).to.equal(0); -}); + }); -it('Validating a simple component that is required but conditionally hidden', async () => { - const component = {...simpleTextField}; + it('Validating a simple component that is required but conditionally hidden', async function () { + const component = { ...simpleTextField }; component.validate = { required: true }; component.conditional = { - show: false, - when: 'otherData', - eq: 'hideme' + show: false, + when: 'otherData', + eq: 'hideme', }; - const data = {otherData: 'hideme'}; + const data = { otherData: 'hideme' }; const context = generateProcessorContext(component, data) as ProcessorsContext; context.processors = [validateProcessInfo]; await processOne(context); expect(context.scope.errors.length).to.equal(0); -}); + }); -it('Validating a simple component that is required but not persistent', async () => { - const component = {...simpleTextField}; + it('Validating a simple component that is required but not persistent', async function () { + const component = { ...simpleTextField }; component.validate = { required: true }; component.persistent = false; - const data = {otherData: 'hideme'}; + const data = { otherData: 'hideme' }; const context = generateProcessorContext(component, data) as ProcessorsContext; context.processors = [validateProcessInfo]; await processOne(context); expect(context.scope.errors.length).to.equal(0); -}); + }); -it('Validating a simple component that is required but persistent set to client-only', async () => { - const component = {...simpleTextField}; + it('Validating a simple component that is required but persistent set to client-only', async function () { + const component = { ...simpleTextField }; component.validate = { required: true }; component.persistent = 'client-only'; - const data = {otherData: 'hideme'}; + const data = { otherData: 'hideme' }; const context = generateProcessorContext(component, data) as ProcessorsContext; context.processors = [validateProcessInfo]; await processOne(context); expect(context.scope.errors.length).to.equal(0); -}); + }); -it('Should not validate a non input comonent', async () => { + it('Should not validate a non input comonent', async function () { const component = requiredNonInputField; const data = {}; const context = generateProcessorContext(component, data) as ProcessorsContext; context.processors = [validateProcessInfo]; await processOne(context); expect(context.scope.errors.length).to.equal(0); -}); + }); -it('Should validate a conditionally hidden component with validateWhenHidden flag set to true', async () => { - const component = {...simpleTextField}; + it('Should validate a conditionally hidden component with validateWhenHidden flag set to true', async function () { + const component = { ...simpleTextField }; component.validate = { required: true }; component.validateWhenHidden = true; component.conditional = { - show: false, - when: 'otherData', - eq: 'hideme' + show: false, + when: 'otherData', + eq: 'hideme', }; - const data = {otherData: 'hideme'}; + const data = { otherData: 'hideme' }; const context = generateProcessorContext(component, data) as ProcessorsContext; context.processors = [validateProcessInfo]; await processOne(context); expect(context.scope.errors.length).to.equal(1); - expect(context.scope.errors[0] && context.scope.errors[0].errorKeyOrMessage).to.equal('required'); -}); - -it('Validating a simple radio component that is required and present in the data with value set to false will return null', async () => { - const component = { ...simpleRadioField, validate: { required: true }, values: [ + expect(context.scope.errors[0] && context.scope.errors[0].errorKeyOrMessage).to.equal( + 'required', + ); + }); + + it('Validating a simple radio component that is required and present in the data with value set to false will return null', async function () { + const component = { + ...simpleRadioField, + validate: { required: true }, + values: [ { - label: 'Yes', - value: 'true', + label: 'Yes', + value: 'true', }, { - label: 'No', - value: 'false', - }] }; + label: 'No', + value: 'false', + }, + ], + }; const data = { component: false }; const context = generateProcessorContext(component, data); const result = await validateRequired(context); expect(result).to.equal(null); -}); - + }); -it('Validating a simple selectbox that is required and present in the data with value set to 0 will return null', async () => { - const component = { ...simpleSelectBoxes, validate: { required: true }, values: [ + it('Validating a simple selectbox that is required and present in the data with value set to 0 will return null', async function () { + const component = { + ...simpleSelectBoxes, + validate: { required: true }, + values: [ { - label: 'true', - value: 'true', + label: 'true', + value: 'true', }, { - label: 'Null', - value: '0', - }] }; + label: 'Null', + value: '0', + }, + ], + }; const data = { component: 0 }; const context = generateProcessorContext(component, data); const result = await validateRequired(context); expect(result).to.equal(null); -}); + }); -it('Validating a simple selectbox that is required and present in the data with value set to false will return a FieldError', async () => { - const component: SelectBoxesComponent = { ...simpleSelectBoxes, validate: { required: true }, values: [ + it('Validating a simple selectbox that is required and present in the data with value set to false will return a FieldError', async function () { + const component: SelectBoxesComponent = { + ...simpleSelectBoxes, + validate: { required: true }, + values: [ { - label: 'true', - value: 'true', + label: 'true', + value: 'true', }, { - label: 'false', - value: 'false', - }] + label: 'false', + value: 'false', + }, + ], }; const data = { - component: { - true: false, - false: false - } + component: { + true: false, + false: false, + }, }; const context = generateProcessorContext(component, data); const result = await validateRequired(context); expect(result).to.be.instanceOf(FieldError); -}); + }); -it('Validating a simple checkbox that is required and present in the data with value set to false will return a FieldError', async () => { + it('Validating a simple checkbox that is required and present in the data with value set to false will return a FieldError', async function () { const component = { ...simpleCheckBoxField, validate: { required: true } }; const data = { component: false }; const context = generateProcessorContext(component, data); const result = await validateRequired(context); expect(result).to.be.instanceOf(FieldError); + }); }); diff --git a/src/process/validation/rules/__tests__/validateRequiredDay.test.ts b/src/process/validation/rules/__tests__/validateRequiredDay.test.ts index 6492843c..7f4a272c 100644 --- a/src/process/validation/rules/__tests__/validateRequiredDay.test.ts +++ b/src/process/validation/rules/__tests__/validateRequiredDay.test.ts @@ -1,53 +1,55 @@ -import {expect} from 'chai' -import {FieldError} from 'error'; -import {simpleDayField} from './fixtures/components'; -import {generateProcessorContext} from "./fixtures/util"; -import {validateRequiredDay} from '../validateRequiredDay' +import { expect } from 'chai'; +import { FieldError } from 'error'; +import { simpleDayField } from './fixtures/components'; +import { generateProcessorContext } from './fixtures/util'; +import { validateRequiredDay } from '../validateRequiredDay'; -it('Validating a day component without data will return a requiredDayEmpty FieldError', async () => { +describe('validateRequiredDay', function () { + it('Validating a day component without data will return a requiredDayEmpty FieldError', async function () { const component = { - ...simpleDayField, - fields: {day: {required: true}, month: {required: false}, year: {required: false}} + ...simpleDayField, + fields: { day: { required: true }, month: { required: false }, year: { required: false } }, }; - const data = {} + const data = {}; const context = generateProcessorContext(component, data); const result = await validateRequiredDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('requiredDayEmpty'); -}); + }); -it('Validating a day component that requires day will return a FieldError if day is not given', async () => { + it('Validating a day component that requires day will return a FieldError if day is not given', async function () { const component = { - ...simpleDayField, - fields: {day: {required: true}} - } - const data = {component: "01/00/2024"}; + ...simpleDayField, + fields: { day: { required: true } }, + }; + const data = { component: '01/00/2024' }; const context = generateProcessorContext(component, data); const result = await validateRequiredDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('requiredDayField'); -}); + }); -it('Validating a day component that requires month will return a FieldError if month is not given', async () => { + it('Validating a day component that requires month will return a FieldError if month is not given', async function () { const component = { - ...simpleDayField, - fields: {month: {required: true}} - } - const data = {component: "00/01/2024"}; + ...simpleDayField, + fields: { month: { required: true } }, + }; + const data = { component: '00/01/2024' }; const context = generateProcessorContext(component, data); const result = await validateRequiredDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('requiredMonthField'); -}); + }); -it('Validating a day component that requires year will return a FieldError if year is not given', async () => { + it('Validating a day component that requires year will return a FieldError if year is not given', async function () { const component = { - ...simpleDayField, - fields: {year: {required: true}} + ...simpleDayField, + fields: { year: { required: true } }, }; - const data = {component: "01/01/0000"}; + const data = { component: '01/01/0000' }; const context = generateProcessorContext(component, data); const result = await validateRequiredDay(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('requiredYearField'); + }); }); diff --git a/src/process/validation/rules/__tests__/validateTime.test.ts b/src/process/validation/rules/__tests__/validateTime.test.ts index ae9adf7c..3dc1f8f4 100644 --- a/src/process/validation/rules/__tests__/validateTime.test.ts +++ b/src/process/validation/rules/__tests__/validateTime.test.ts @@ -6,41 +6,43 @@ import { generateProcessorContext } from './fixtures/util'; import { validateTime } from '../validateTime'; const timeField: TimeComponent = { - type: 'time', - key: 'time', - label: 'Time', - input: true, - dataFormat: 'HH:mm:ss', - format: 'HH:mm' + type: 'time', + key: 'time', + label: 'Time', + input: true, + dataFormat: 'HH:mm:ss', + format: 'HH:mm', }; -it('Should validate a time component with a valid time value', async () => { +describe('validateTime', function () { + it('Should validate a time component with a valid time value', async function () { const data = { time: '12:00:00' }; const context = generateProcessorContext(timeField, data); const result = await validateTime(context); expect(result).to.equal(null); -}); + }); -it('Should return a FieldError when validating a time component with an invalid time value', async () => { + it('Should return a FieldError when validating a time component with an invalid time value', async function () { const data = { time: '25:00:00' }; const context = generateProcessorContext(timeField, data); const result = await validateTime(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.contain('time'); -}); + }); -it('Should return a FieldError when validating a time component with a valid format but one that does not match the dataFormat', async () => { + it('Should return a FieldError when validating a time component with a valid format but one that does not match the dataFormat', async function () { const data = { time: '12:00' }; const context = generateProcessorContext(timeField, data); const result = await validateTime(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.contain('time'); -}); + }); -it('Should return a FieldError when validating a time component with an invalid format', async () => { + it('Should return a FieldError when validating a time component with an invalid format', async function () { const data = { time: '12:' }; const context = generateProcessorContext(timeField, data); const result = await validateTime(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.contain('time'); + }); }); diff --git a/src/process/validation/rules/__tests__/validateUrl.test.ts b/src/process/validation/rules/__tests__/validateUrl.test.ts index 027af5f8..dcbec5a6 100644 --- a/src/process/validation/rules/__tests__/validateUrl.test.ts +++ b/src/process/validation/rules/__tests__/validateUrl.test.ts @@ -5,86 +5,88 @@ import { simpleUrlField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateUrl } from '../validateUrl'; -it('Validating a URL component whose data contains an invalid URL returns a FieldError', async () => { +describe('validateUrl', function () { + it('Validating a URL component whose data contains an invalid URL returns a FieldError', async function () { const component = simpleUrlField; const data = { - component: 'htp:/ww.google', + component: 'htp:/ww.google', }; const context = generateProcessorContext(component, data); const result = await validateUrl(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.contain('invalid_url'); -}); + }); -it('Validating a URL component whose data contains an invalid URL returns a FieldError', async () => { + it('Validating a URL component whose data contains a nonsense URL returns a FieldError', async function () { const component = simpleUrlField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateUrl(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.contain('invalid_url'); -}); + }); -// it('Validating a URL component whose data contains an valid URL that is not HTTP or HTTPS returns a FieldError', async () => { -// const component = simpleUrlField; -// const data = { -// component: 'ftp://www.google.com', -// }; -// const context = generateProcessContext(component, data); -// const result = await validateUrl(context); -// expect(result).to.be.instanceOf(FieldError); -// expect(result?.errorKeyOrMessage).to.contain('invalid_url'); -// }); + xit('Validating a URL component whose data contains an valid URL that is not HTTP or HTTPS (ftp) returns a FieldError', async function () { + const component = simpleUrlField; + const data = { + component: 'ftp://www.google.com', + }; + const context = generateProcessorContext(component, data); + const result = await validateUrl(context); + expect(result).to.be.instanceOf(FieldError); + expect(result?.errorKeyOrMessage).to.contain('invalid_url'); + }); -// it('Validating a URL component whose data contains an valid URL that is not HTTP or HTTPS returns a FieldError', async () => { -// const component = simpleUrlField; -// const data = { -// component: 'mailto://www.google.com', -// }; -// const context = generateProcessContext(component, data); -// const result = await validateUrl(context); -// expect(result).to.be.instanceOf(FieldError); -// expect(result?.errorKeyOrMessage).to.contain('invalid_url'); -// }); + xit('Validating a URL component whose data contains an valid URL that is not HTTP or HTTPS (mailto) returns a FieldError', async function () { + const component = simpleUrlField; + const data = { + component: 'mailto://www.google.com', + }; + const context = generateProcessorContext(component, data); + const result = await validateUrl(context); + expect(result).to.be.instanceOf(FieldError); + expect(result?.errorKeyOrMessage).to.contain('invalid_url'); + }); -it('Validating a URL component whose data contains a valid HTTPS URL returns null', async () => { + it('Validating a URL component whose data contains a valid HTTPS URL returns null', async function () { const component = simpleUrlField; const data = { - component: 'https://www.google.com', + component: 'https://www.google.com', }; const context = generateProcessorContext(component, data); const result = await validateUrl(context); expect(result).to.equal(null); -}); + }); -it('Validating a URL component whose data contains a valid HTTP URL returns null', async () => { + it('Validating a URL component whose data contains a valid HTTP URL returns null', async function () { const component = simpleUrlField; const data = { - component: 'http://www.google.com', + component: 'http://www.google.com', }; const context = generateProcessorContext(component, data); const result = await validateUrl(context); expect(result).to.equal(null); -}); + }); -// it('Validating a URL component whose data contains a valid localhost URL returns null', async () => { -// const component = simpleUrlField; -// const data = { -// component: 'http://localhost:3000', -// }; -// const context = generateProcessContext(component, data); -// const result = await validateUrl(context); -// expect(result).to.equal(null); -// }); + xit('Validating a URL component whose data contains a valid localhost URL returns null', async function () { + const component = simpleUrlField; + const data = { + component: 'http://localhost:3000', + }; + const context = generateProcessorContext(component, data); + const result = await validateUrl(context); + expect(result).to.equal(null); + }); -it('Validating a URL component whose data contains a strange but valid URL returns null', async () => { + it('Validating a URL component whose data contains a strange but valid URL returns null', async function () { const component = simpleUrlField; const data = { - component: 'www.hhh.by', + component: 'www.hhh.by', }; const context = generateProcessorContext(component, data); const result = await validateUrl(context); expect(result).to.equal(null); -}) + }); +}); diff --git a/src/process/validation/rules/__tests__/validateUrlSelectValue.test.ts b/src/process/validation/rules/__tests__/validateUrlSelectValue.test.ts index 9b1e3603..04f025e9 100644 --- a/src/process/validation/rules/__tests__/validateUrlSelectValue.test.ts +++ b/src/process/validation/rules/__tests__/validateUrlSelectValue.test.ts @@ -6,139 +6,141 @@ import { simpleSelectOptions, simpleTextField } from './fixtures/components'; import { generateProcessorContext } from './fixtures/util'; import { validateUrlSelectValue, generateUrl } from '../validateUrlSelectValue'; -it('Validating a component without the remote value validation parameter will return null', async () => { +describe('validateUrlSelectValue', function () { + it('Validating a component without the remote value validation parameter will return null', async function () { const component = simpleTextField; const data = { - component: 'Hello, world!', + component: 'Hello, world!', }; const context = generateProcessorContext(component, data); const result = await validateUrlSelectValue(context); expect(result).to.equal(null); -}); + }); -it('Validating a select component without the remote value validation parameter will return null', async () => { + it('Validating a select component without the remote value validation parameter will return null', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'url', - data: { - url: 'http://localhost:8080/numbers', - headers: [], - }, + ...simpleSelectOptions, + dataSrc: 'url', + data: { + url: 'http://localhost:8080/numbers', + headers: [], + }, }; const data = { - component: { - id: 'b', - value: 2, - }, + component: { + id: 'b', + value: 2, + }, }; const context = generateProcessorContext(component, data); const result = await validateUrlSelectValue(context); expect(result).to.equal(null); -}); + }); -it('The remote value validation will generate the correct URL given a searchField and a valueProperty', async () => { + it('The remote value validation will generate the correct URL given a searchField and a valueProperty', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'url', - data: { - url: 'http://localhost:8080/numbers', - headers: [], - }, - searchField: 'number', - valueProperty: 'value', - validate: { select: true }, + ...simpleSelectOptions, + dataSrc: 'url', + data: { + url: 'http://localhost:8080/numbers', + headers: [], + }, + searchField: 'number', + valueProperty: 'value', + validate: { select: true }, }; const data: DataObject = { - component: { - id: 'b', - value: 2, - }, + component: { + id: 'b', + value: 2, + }, }; const value = get(data, component.key); if (!component.data || !component.data.url) { - throw new Error('Component passed to remote validation testing does not contain a URL'); + throw new Error('Component passed to remote validation testing does not contain a URL'); } const baseUrl = new URL(component.data.url); const result = generateUrl(baseUrl, component, value); expect(result).to.be.instanceOf(URL); expect(result.href).to.equal(`http://localhost:8080/numbers?number=2`); -}); + }); -it('Validating a select component with the remote validation parameter will return a FieldError if the value does not exist and the API returns an array', async () => { + it('Validating a select component with the remote validation parameter will return a FieldError if the value does not exist and the API returns an array', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'url', - data: { - url: 'http://localhost:8080/numbers', - headers: [], - }, - searchField: 'number', - valueProperty: 'value', - validate: { select: true }, + ...simpleSelectOptions, + dataSrc: 'url', + data: { + url: 'http://localhost:8080/numbers', + headers: [], + }, + searchField: 'number', + valueProperty: 'value', + validate: { select: true }, }; const data = { - component: { - id: 'b', - value: 2, - }, + component: { + id: 'b', + value: 2, + }, }; const context = generateProcessorContext(component, data); const result = await validateUrlSelectValue(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('select'); -}); + }); -it('Validating a select component with the remote validation parameter will return a FieldError if the value does not exist and the API returns an object', async () => { + it('Validating a select component with the remote validation parameter will return a FieldError if the value does not exist and the API returns an object', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'url', - data: { - url: 'http://localhost:8080/numbers', - headers: [], - }, - searchField: 'number', - valueProperty: 'value', - validate: { select: true }, + ...simpleSelectOptions, + dataSrc: 'url', + data: { + url: 'http://localhost:8080/numbers', + headers: [], + }, + searchField: 'number', + valueProperty: 'value', + validate: { select: true }, }; const data = { - component: { - id: 'b', - value: 2, - }, + component: { + id: 'b', + value: 2, + }, }; const context = generateProcessorContext(component, data); const result = await validateUrlSelectValue(context); expect(result).to.be.instanceOf(FieldError); expect(result?.errorKeyOrMessage).to.equal('select'); -}); + }); -it('Validating a select component with the remote validation parameter will return null if the value exists', async () => { + it('Validating a select component with the remote validation parameter will return null if the value exists', async function () { const component: SelectComponent = { - ...simpleSelectOptions, - dataSrc: 'url', - data: { - url: 'http://localhost:8080/numbers', - headers: [], - }, - searchField: 'number', - valueProperty: 'value', - validate: { select: true }, + ...simpleSelectOptions, + dataSrc: 'url', + data: { + url: 'http://localhost:8080/numbers', + headers: [], + }, + searchField: 'number', + valueProperty: 'value', + validate: { select: true }, }; const data = { - component: { - id: 'b', - value: 2, - }, + component: { + id: 'b', + value: 2, + }, }; const context = generateProcessorContext(component, data); - context.fetch = (url: string, options?: RequestInit | undefined) => { - return Promise.resolve({ - ok: true, - json: () => Promise.resolve([{ id: 'b', value: 2 }]) - }); + context.fetch = () => { + return Promise.resolve({ + ok: true, + json: () => Promise.resolve([{ id: 'b', value: 2 }]), + }); }; const result = await validateUrlSelectValue(context); expect(result).to.equal(null); + }); }); diff --git a/src/process/validation/rules/asynchronousRules.ts b/src/process/validation/rules/asynchronousRules.ts index 4b2fc2c8..cae24d97 100644 --- a/src/process/validation/rules/asynchronousRules.ts +++ b/src/process/validation/rules/asynchronousRules.ts @@ -1,9 +1,9 @@ -import { ValidationRuleInfo } from "types"; -import { validateUrlSelectValueInfo } from "./validateUrlSelectValue"; -import { validateAvailableItemsInfo } from "./validateAvailableItems"; +import { ValidationRuleInfo } from 'types'; +import { validateUrlSelectValueInfo } from './validateUrlSelectValue'; +import { validateAvailableItemsInfo } from './validateAvailableItems'; // These are the validations that are asynchronouse (e.g. require fetch export const asynchronousRules: ValidationRuleInfo[] = [ - validateUrlSelectValueInfo, - validateAvailableItemsInfo + validateUrlSelectValueInfo, + validateAvailableItemsInfo, ]; diff --git a/src/process/validation/rules/clientRules.ts b/src/process/validation/rules/clientRules.ts index cb6b1c35..e52cdd78 100644 --- a/src/process/validation/rules/clientRules.ts +++ b/src/process/validation/rules/clientRules.ts @@ -1,55 +1,55 @@ -import { ValidationRuleInfo } from "types"; -import { validateDateInfo } from "./validateDate"; -import { validateDayInfo } from "./validateDay"; -import { validateEmailInfo } from "./validateEmail"; -import { validateJsonInfo } from "./validateJson"; -import { validateMaskInfo } from "./validateMask"; -import { validateMaximumDayInfo } from "./validateMaximumDay"; -import { validateMaximumLengthInfo } from "./validateMaximumLength"; -import { validateMaximumSelectedCountInfo } from "./validateMaximumSelectedCount"; -import { validateMaximumValueInfo } from "./validateMaximumValue"; -import { validateMaximumWordsInfo } from "./validateMaximumWords"; -import { validateMaximumYearInfo } from "./validateMaximumYear"; -import { validateMinimumDayInfo } from "./validateMinimumDay"; -import { validateMinimumLengthInfo } from "./validateMinimumLength"; -import { validateMinimumSelectedCountInfo } from "./validateMinimumSelectedCount"; -import { validateMinimumValueInfo } from "./validateMinimumValue"; -import { validateMinimumWordsInfo } from "./validateMinimumWords"; -import { validateMinimumYearInfo } from "./validateMinimumYear"; -import { validateMultipleInfo } from "./validateMultiple"; -import { validateRegexPatternInfo } from "./validateRegexPattern"; -import { validateRequiredInfo } from "./validateRequired"; -import { validateRequiredDayInfo } from "./validateRequiredDay"; -import { validateTimeInfo } from "./validateTime"; -import { validateUrlInfo } from "./validateUrl"; -import { validateValuePropertyInfo } from "./validateValueProperty"; -import { validateNumberInfo } from "./validateNumber"; +import { ValidationRuleInfo } from 'types'; +import { validateDateInfo } from './validateDate'; +import { validateDayInfo } from './validateDay'; +import { validateEmailInfo } from './validateEmail'; +import { validateJsonInfo } from './validateJson'; +import { validateMaskInfo } from './validateMask'; +import { validateMaximumDayInfo } from './validateMaximumDay'; +import { validateMaximumLengthInfo } from './validateMaximumLength'; +import { validateMaximumSelectedCountInfo } from './validateMaximumSelectedCount'; +import { validateMaximumValueInfo } from './validateMaximumValue'; +import { validateMaximumWordsInfo } from './validateMaximumWords'; +import { validateMaximumYearInfo } from './validateMaximumYear'; +import { validateMinimumDayInfo } from './validateMinimumDay'; +import { validateMinimumLengthInfo } from './validateMinimumLength'; +import { validateMinimumSelectedCountInfo } from './validateMinimumSelectedCount'; +import { validateMinimumValueInfo } from './validateMinimumValue'; +import { validateMinimumWordsInfo } from './validateMinimumWords'; +import { validateMinimumYearInfo } from './validateMinimumYear'; +import { validateMultipleInfo } from './validateMultiple'; +import { validateRegexPatternInfo } from './validateRegexPattern'; +import { validateRequiredInfo } from './validateRequired'; +import { validateRequiredDayInfo } from './validateRequiredDay'; +import { validateTimeInfo } from './validateTime'; +import { validateUrlInfo } from './validateUrl'; +import { validateValuePropertyInfo } from './validateValueProperty'; +import { validateNumberInfo } from './validateNumber'; // These are the validations that are performed in the client. export const clientRules: ValidationRuleInfo[] = [ - validateDateInfo, - validateDayInfo, - validateEmailInfo, - validateJsonInfo, - validateMaskInfo, - validateMaximumDayInfo, - validateMaximumLengthInfo, - validateMaximumSelectedCountInfo, - validateMaximumValueInfo, - validateMaximumWordsInfo, - validateMaximumYearInfo, - validateMinimumDayInfo, - validateMinimumLengthInfo, - validateMinimumSelectedCountInfo, - validateMinimumValueInfo, - validateMinimumWordsInfo, - validateMinimumYearInfo, - validateMultipleInfo, - validateRegexPatternInfo, - validateRequiredInfo, - validateRequiredDayInfo, - validateTimeInfo, - validateUrlInfo, - validateValuePropertyInfo, - validateNumberInfo + validateDateInfo, + validateDayInfo, + validateEmailInfo, + validateJsonInfo, + validateMaskInfo, + validateMaximumDayInfo, + validateMaximumLengthInfo, + validateMaximumSelectedCountInfo, + validateMaximumValueInfo, + validateMaximumWordsInfo, + validateMaximumYearInfo, + validateMinimumDayInfo, + validateMinimumLengthInfo, + validateMinimumSelectedCountInfo, + validateMinimumValueInfo, + validateMinimumWordsInfo, + validateMinimumYearInfo, + validateMultipleInfo, + validateRegexPatternInfo, + validateRequiredInfo, + validateRequiredDayInfo, + validateTimeInfo, + validateUrlInfo, + validateValuePropertyInfo, + validateNumberInfo, ]; diff --git a/src/process/validation/rules/databaseRules.ts b/src/process/validation/rules/databaseRules.ts index 667dd25c..a4cc0822 100644 --- a/src/process/validation/rules/databaseRules.ts +++ b/src/process/validation/rules/databaseRules.ts @@ -1,9 +1,9 @@ -import { ValidationRuleInfo } from "types"; -import { validateUniqueInfo } from "./validateUnique"; -import { validateResourceSelectValueInfo } from "./validateResourceSelectValue"; +import { ValidationRuleInfo } from 'types'; +import { validateUniqueInfo } from './validateUnique'; +import { validateResourceSelectValueInfo } from './validateResourceSelectValue'; // These are the validations that require a database connection. export const databaseRules: ValidationRuleInfo[] = [ - validateUniqueInfo, - validateResourceSelectValueInfo + validateUniqueInfo, + validateResourceSelectValueInfo, ]; diff --git a/src/process/validation/rules/evaluationRules.ts b/src/process/validation/rules/evaluationRules.ts index b14353a2..96f37f60 100644 --- a/src/process/validation/rules/evaluationRules.ts +++ b/src/process/validation/rules/evaluationRules.ts @@ -1,7 +1,7 @@ -import { ValidationRuleInfo } from "types"; -import { validateCustomInfo } from "./validateCustom"; -import { validateAvailableItemsInfo } from "./validateAvailableItems"; +import { ValidationRuleInfo } from 'types'; +import { validateCustomInfo } from './validateCustom'; +import { validateAvailableItemsInfo } from './validateAvailableItems'; export const evaluationRules: ValidationRuleInfo[] = [ - validateCustomInfo, - validateAvailableItemsInfo + validateCustomInfo, + validateAvailableItemsInfo, ]; diff --git a/src/process/validation/rules/validateAvailableItems.ts b/src/process/validation/rules/validateAvailableItems.ts index 64c361b9..e0db8496 100644 --- a/src/process/validation/rules/validateAvailableItems.ts +++ b/src/process/validation/rules/validateAvailableItems.ts @@ -1,337 +1,348 @@ -import { isEmpty, isUndefined} from 'lodash'; +import { isEmpty, isUndefined } from 'lodash'; import { FieldError, ProcessorError } from 'error'; import { Evaluator } from 'utils'; -import { RadioComponent, SelectComponent, RuleFn, RuleFnSync, ValidationContext, FetchFn, SelectBoxesComponent } from 'types'; +import { + RadioComponent, + SelectComponent, + RuleFn, + RuleFnSync, + ValidationContext, + FetchFn, + SelectBoxesComponent, +} from 'types'; import { isObject, isPromise } from '../util'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; import { getErrorMessage } from 'utils/error'; function isValidatableRadioComponent(component: any): component is RadioComponent { - return ( - component && - component.type === 'radio' && - !!component.validate?.onlyAvailableItems - ); + return component && component.type === 'radio' && !!component.validate?.onlyAvailableItems; } function isValidateableSelectComponent(component: any): component is SelectComponent { - return ( - component && - !!component.validate?.onlyAvailableItems && - component.type === 'select' && - component.dataSrc !== 'resource' - ); + return ( + component && + !!component.validate?.onlyAvailableItems && + component.type === 'select' && + component.dataSrc !== 'resource' + ); } function isValidateableSelectBoxesComponent(component: any): component is SelectBoxesComponent { - return ( - component && - !!component.validate?.onlyAvailableItems && - component.type === 'selectboxes' && - component.dataSrc === 'url' - ); + return ( + component && + !!component.validate?.onlyAvailableItems && + component.type === 'selectboxes' && + component.dataSrc === 'url' + ); } function mapDynamicValues>(component: SelectComponent, values: T[]) { - return values.map((value) => { - if (component.valueProperty) { - return value[component.valueProperty]; - } - return value; - }); + return values.map((value) => { + if (component.valueProperty) { + return value[component.valueProperty]; + } + return value; + }); } function mapStaticValues(values: { label: string; value: string }[]) { - return values.map((obj) => obj.value); + return values.map((obj) => obj.value); } const getAvailableDynamicValues = async (component: any, context: ValidationContext) => { - let _fetch: FetchFn | null = null; - try { - _fetch = context.fetch ? context.fetch : fetch; - } - catch (err) { - _fetch = null; - } - try { - if (!_fetch) { - console.log('You must provide a fetch interface to the fetch processor.'); - return null; - } - const response = await _fetch((component as any).data.url, { method: 'GET' }); - const data = await response.json(); - return data ? mapDynamicValues(component, data) : null; - } - catch (err) { - console.error(getErrorMessage(err)); - return null; + let _fetch: FetchFn | null = null; + try { + _fetch = context.fetch ? context.fetch : fetch; + } catch (ignoreErr) { + _fetch = null; + } + try { + if (!_fetch) { + console.log('You must provide a fetch interface to the fetch processor.'); + return null; } -} + const response = await _fetch((component as any).data.url, { method: 'GET' }); + const data = await response.json(); + return data ? mapDynamicValues(component, data) : null; + } catch (err) { + console.error(getErrorMessage(err)); + return null; + } +}; async function getAvailableSelectValues(component: SelectComponent, context: ValidationContext) { - if (isUndefined(component.dataSrc) && component.data.hasOwnProperty('values')) { - component.dataSrc = 'values'; - }; - switch (component.dataSrc) { - case 'values': - if (Array.isArray(component.data.values)) { - return mapStaticValues(component.data.values); - } - throw new ProcessorError( - `Failed to validate available values in static values select component '${component.key}': the values are not an array`, - context, - 'validate:validateAvailableItems' - ); - case 'json': { - if (typeof component.data.json === 'string') { - try { - return mapDynamicValues(component, JSON.parse(component.data.json)); - } catch (err) { - throw new ProcessorError( - `Failed to validate available values in JSON select component '${component.key}': ${err}`, - context, - 'validate:validateAvailableItems' - ); - } - } else if (Array.isArray(component.data.json)) { - // TODO: need to retype this - return mapDynamicValues(component, component.data.json as Record[]); - } else { - throw new ProcessorError( - `Failed to validate available values in JSON select component '${component.key}': the values are not an array`, - context, - 'validate:validateAvailableItems' - ); - } + if (isUndefined(component.dataSrc) && component.data.hasOwnProperty('values')) { + component.dataSrc = 'values'; + } + switch (component.dataSrc) { + case 'values': + if (Array.isArray(component.data.values)) { + return mapStaticValues(component.data.values); + } + throw new ProcessorError( + `Failed to validate available values in static values select component '${component.key}': the values are not an array`, + context, + 'validate:validateAvailableItems', + ); + case 'json': { + if (typeof component.data.json === 'string') { + try { + return mapDynamicValues(component, JSON.parse(component.data.json)); + } catch (err) { + throw new ProcessorError( + `Failed to validate available values in JSON select component '${component.key}': ${err}`, + context, + 'validate:validateAvailableItems', + ); + } + } else if (Array.isArray(component.data.json)) { + // TODO: need to retype this + return mapDynamicValues(component, component.data.json as Record[]); + } else { + throw new ProcessorError( + `Failed to validate available values in JSON select component '${component.key}': the values are not an array`, + context, + 'validate:validateAvailableItems', + ); + } + } + case 'custom': { + const customItems = Evaluator.evaluate( + component.data.custom, + { + values: [], + }, + 'values', + ); + if (isPromise(customItems)) { + const resolvedCustomItems = await customItems; + if (Array.isArray(resolvedCustomItems)) { + return resolvedCustomItems; } - case 'custom': - const customItems = Evaluator.evaluate( - component.data.custom, - { - values: [], - }, - 'values' - ); - if (isPromise(customItems)) { - const resolvedCustomItems = await customItems; - if (Array.isArray(resolvedCustomItems)) { - return resolvedCustomItems; - } - throw new ProcessorError( - `Failed to validate available values in JSON select component '${component.key}': the values are not an array`, - context, - 'validate:validateAvailableItems' - ); - } - if (Array.isArray(customItems)) { - return customItems; - } else { - throw new ProcessorError( - `Failed to validate available values in JSON select component '${component.key}': the values are not an array`, - context, - 'validate:validateAvailableItems' - ); - } - case 'url': - return await getAvailableDynamicValues(component, context); - default: - throw new ProcessorError( - `Failed to validate available values in select component '${component.key}': data source ${component.dataSrc} is not valid}`, - context, - 'validate:validateAvailableItems' - ); + throw new ProcessorError( + `Failed to validate available values in JSON select component '${component.key}': the values are not an array`, + context, + 'validate:validateAvailableItems', + ); + } + if (Array.isArray(customItems)) { + return customItems; + } else { + throw new ProcessorError( + `Failed to validate available values in JSON select component '${component.key}': the values are not an array`, + context, + 'validate:validateAvailableItems', + ); + } } + case 'url': + return await getAvailableDynamicValues(component, context); + default: + throw new ProcessorError( + `Failed to validate available values in select component '${component.key}': data source ${component.dataSrc} is not valid}`, + context, + 'validate:validateAvailableItems', + ); + } } function getAvailableSelectValuesSync(component: SelectComponent, context: ValidationContext) { - if (isUndefined(component.dataSrc) && component.data.hasOwnProperty('values')) { - component.dataSrc = 'values'; - }; - switch (component.dataSrc) { - case 'values': - if (Array.isArray(component.data?.values)) { - return mapStaticValues(component.data.values); - } - throw new ProcessorError( - `Failed to validate available values in static values select component '${component.key}': the values are not an array`, - context, - 'validate:validateAvailableItems' - ); - case 'json': { - if (typeof component.data.json === 'string') { - try { - return mapDynamicValues(component, JSON.parse(component.data.json)); - } catch (err) { - throw new ProcessorError( - `Failed to validate available values in JSON select component '${component.key}': ${err}`, - context, - 'validate:validateAvailableItems' - ); - } - } else if (Array.isArray(component.data.json)) { - // TODO: need to retype this - return mapDynamicValues(component, component.data.json as Record[]); - } else { - throw new ProcessorError( - `Failed to validate available values in JSON select component '${component.key}': the values are not an array`, - context, - 'validate:validateAvailableItems' - ); - } + if (isUndefined(component.dataSrc) && component.data.hasOwnProperty('values')) { + component.dataSrc = 'values'; + } + switch (component.dataSrc) { + case 'values': + if (Array.isArray(component.data?.values)) { + return mapStaticValues(component.data.values); + } + throw new ProcessorError( + `Failed to validate available values in static values select component '${component.key}': the values are not an array`, + context, + 'validate:validateAvailableItems', + ); + case 'json': { + if (typeof component.data.json === 'string') { + try { + return mapDynamicValues(component, JSON.parse(component.data.json)); + } catch (err) { + throw new ProcessorError( + `Failed to validate available values in JSON select component '${component.key}': ${err}`, + context, + 'validate:validateAvailableItems', + ); } - case 'custom': - const customItems = Evaluator.evaluate( - component.data.custom, - { - values: [], - }, - 'values' - ); - if (Array.isArray(customItems)) { - return customItems; - } else { - throw new ProcessorError( - `Failed to validate available values in JSON select component '${component.key}': the values are not an array`, - context, - 'validate:validateAvailableItems' - ); - } - case 'url': - return null; - default: - throw new ProcessorError( - `Failed to validate available values in select component '${component.key}': data source ${component.dataSrc} is not valid}`, - context, - 'validate:validateAvailableItems' - ); + } else if (Array.isArray(component.data.json)) { + // TODO: need to retype this + return mapDynamicValues(component, component.data.json as Record[]); + } else { + throw new ProcessorError( + `Failed to validate available values in JSON select component '${component.key}': the values are not an array`, + context, + 'validate:validateAvailableItems', + ); + } } + case 'custom': { + const customItems = Evaluator.evaluate( + component.data.custom, + { + values: [], + }, + 'values', + ); + if (Array.isArray(customItems)) { + return customItems; + } else { + throw new ProcessorError( + `Failed to validate available values in JSON select component '${component.key}': the values are not an array`, + context, + 'validate:validateAvailableItems', + ); + } + } + case 'url': + return null; + default: + throw new ProcessorError( + `Failed to validate available values in select component '${component.key}': data source ${component.dataSrc} is not valid}`, + context, + 'validate:validateAvailableItems', + ); + } } function compareComplexValues(valueA: unknown, valueB: unknown, context: ValidationContext) { - if (!isObject(valueA) || !isObject(valueB)) { - return false; - } + if (!isObject(valueA) || !isObject(valueB)) { + return false; + } - try { - // TODO: we need to have normalized values here at this moment, otherwise - // this won't work - return JSON.stringify(valueA) === JSON.stringify(valueB); - } catch (err) { - throw new ProcessorError(`Error while comparing available values: ${err}`, context, 'validate:validateAvailableItems'); - } + try { + // TODO: we need to have normalized values here at this moment, otherwise + // this won't work + return JSON.stringify(valueA) === JSON.stringify(valueB); + } catch (err) { + throw new ProcessorError( + `Error while comparing available values: ${err}`, + context, + 'validate:validateAvailableItems', + ); + } } export const validateAvailableItems: RuleFn = async (context: ValidationContext) => { - const { component, value } = context; - const error = new FieldError('invalidOption', context, 'onlyAvailableItems'); - try { - if (isValidatableRadioComponent(component)) { - if (value == null || isEmpty(value)) { - return null; - } - - const values = component.dataSrc === 'url' ? await getAvailableDynamicValues(component, context) : component.values; - if (values) { - if (isObject(value)) { - return values.find((optionValue) => compareComplexValues(optionValue, value, context)) !== - undefined - ? null - : error; - } - return values.find((optionValue) => optionValue === value) !== undefined ? null : error; - } + const { component, value } = context; + const error = new FieldError('invalidOption', context, 'onlyAvailableItems'); + try { + if (isValidatableRadioComponent(component)) { + if (value == null || isEmpty(value)) { + return null; + } - return null; - } else if (isValidateableSelectComponent(component)) { - if (value == null || isEmpty(value)) { - return null; - } - const values = await getAvailableSelectValues(component, context); - if (values) { - if (isObject(value)) { - return values.find((optionValue) => compareComplexValues(optionValue, value, context)) !== - undefined - ? null - : error; - } + const values = + component.dataSrc === 'url' + ? await getAvailableDynamicValues(component, context) + : component.values; + if (values) { + if (isObject(value)) { + return values.find((optionValue) => compareComplexValues(optionValue, value, context)) !== + undefined + ? null + : error; + } + return values.find((optionValue) => optionValue === value) !== undefined ? null : error; + } - return values.find((optionValue) => optionValue === value) !== undefined ? null : error; - } - } else if (isValidateableSelectBoxesComponent(component)) { - if (value == null || isEmpty(value)) { - return null; - } - const values = await getAvailableDynamicValues(component, context); - if (values) { - if (isObject(value)) { - return values.find((optionValue) => compareComplexValues(optionValue, value, context)) !== - undefined - ? null - : error; - } + return null; + } else if (isValidateableSelectComponent(component)) { + if (value == null || isEmpty(value)) { + return null; + } + const values = await getAvailableSelectValues(component, context); + if (values) { + if (isObject(value)) { + return values.find((optionValue) => compareComplexValues(optionValue, value, context)) !== + undefined + ? null + : error; + } - return values.find((optionValue) => optionValue === value) !== undefined ? null : error; - } + return values.find((optionValue) => optionValue === value) !== undefined ? null : error; + } + } else if (isValidateableSelectBoxesComponent(component)) { + if (value == null || isEmpty(value)) { + return null; + } + const values = await getAvailableDynamicValues(component, context); + if (values) { + if (isObject(value)) { + return values.find((optionValue) => compareComplexValues(optionValue, value, context)) !== + undefined + ? null + : error; } - } catch (err: any) { - throw new ProcessorError(err.message || err, context, 'validate:validateAvailableItems'); + + return values.find((optionValue) => optionValue === value) !== undefined ? null : error; + } } - return null; + } catch (err: any) { + throw new ProcessorError(err.message || err, context, 'validate:validateAvailableItems'); + } + return null; }; export const shouldValidate = (context: any) => { - const { component, value } = context; - if (value == null || isEmpty(value)) { - return false; - } - if (isValidatableRadioComponent(component)) { - return true; - } - if (isValidateableSelectComponent(component)) { - return true; - } - if (isValidateableSelectBoxesComponent(component)) { - return true; - } + const { component, value } = context; + if (value == null || isEmpty(value)) { return false; -} + } + if (isValidatableRadioComponent(component)) { + return true; + } + if (isValidateableSelectComponent(component)) { + return true; + } + if (isValidateableSelectBoxesComponent(component)) { + return true; + } + return false; +}; export const validateAvailableItemsSync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - const error = new FieldError('invalidOption', context, 'onlyAvailableItems'); - try { - if (!shouldValidate(context)) { - return null; - } - if (isValidatableRadioComponent(component) && component.dataSrc !== 'url') { - const values = component.values; - if (values) { - return values.findIndex(({ value: optionValue }) => optionValue === value) !== -1 - ? null - : error; - } - return null; - } else if (isValidateableSelectComponent(component)) { - const values = getAvailableSelectValuesSync(component, context); - if (values) { - if (isObject(value)) { - return values.find((optionValue) => compareComplexValues(optionValue, value, context)) !== - undefined - ? null - : error; - } - return values.find((optionValue) => optionValue === value) !== undefined ? null : error; - } + const { component, value } = context; + const error = new FieldError('invalidOption', context, 'onlyAvailableItems'); + try { + if (!shouldValidate(context)) { + return null; + } + if (isValidatableRadioComponent(component) && component.dataSrc !== 'url') { + const values = component.values; + if (values) { + return values.findIndex(({ value: optionValue }) => optionValue === value) !== -1 + ? null + : error; + } + return null; + } else if (isValidateableSelectComponent(component)) { + const values = getAvailableSelectValuesSync(component, context); + if (values) { + if (isObject(value)) { + return values.find((optionValue) => compareComplexValues(optionValue, value, context)) !== + undefined + ? null + : error; } - } catch (err: any) { - throw new ProcessorError(err.message || err, context, 'validate:validateAvailableItems'); + return values.find((optionValue) => optionValue === value) !== undefined ? null : error; + } } - return null; + } catch (err: any) { + throw new ProcessorError(err.message || err, context, 'validate:validateAvailableItems'); + } + return null; }; export const validateAvailableItemsInfo: ProcessorInfo = { - name: 'validateAvailableItems', - process: validateAvailableItems, - processSync: validateAvailableItemsSync, - shouldProcess: shouldValidate + name: 'validateAvailableItems', + process: validateAvailableItems, + processSync: validateAvailableItemsSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateCustom.ts b/src/process/validation/rules/validateCustom.ts index 52490a7e..960b150a 100644 --- a/src/process/validation/rules/validateCustom.ts +++ b/src/process/validation/rules/validateCustom.ts @@ -1,67 +1,66 @@ -import { isEmpty } from 'lodash'; import { RuleFn, RuleFnSync, ProcessorInfo, ValidationContext } from 'types'; import { FieldError, ProcessorError } from 'error'; import { Evaluator } from 'utils'; export const validateCustom: RuleFn = async (context: ValidationContext) => { - return validateCustomSync(context); + return validateCustomSync(context); }; export const shouldValidate = (context: ValidationContext) => { - const { component } = context; - const customValidation = component.validate?.custom; - if (!customValidation) { - return false; - } - return true; -} + const { component } = context; + const customValidation = component.validate?.custom; + if (!customValidation) { + return false; + } + return true; +}; export const validateCustomSync: RuleFnSync = (context: ValidationContext) => { - const { component, data, row, value, index, instance, evalContext } = context; - const customValidation = component.validate?.custom; - try { - if (!shouldValidate(context)) { - return null; - } - - const evalContextValue = { - ...(instance?.evalContext ? instance.evalContext() : (evalContext ? evalContext(context) : context)), - component, - data, - row, - rowIndex: index, - instance, - valid: true, - input: value, - } + const { component, data, row, value, index, instance, evalContext } = context; + const customValidation = component.validate?.custom; + try { + if (!shouldValidate(context)) { + return null; + } - const isValid = Evaluator.evaluate( - customValidation, - evalContextValue, - 'valid', - true, - {}, - {} - ); + const evalContextValue = { + ...(instance?.evalContext + ? instance.evalContext() + : evalContext + ? evalContext(context) + : context), + component, + data, + row, + rowIndex: index, + instance, + valid: true, + input: value, + }; - if (isValid === null || isValid === true) { - return null; - } + const isValid = Evaluator.evaluate(customValidation, evalContextValue, 'valid', true, {}, {}); - return new FieldError(typeof isValid === 'string' ? isValid : 'custom', { - ...context, - hasLabel: false, - setting: customValidation - }, 'custom'); - } catch (err: any) { - throw new ProcessorError(err.message || err, context, 'validate:validateCustom'); + if (isValid === null || isValid === true) { + return null; } -}; + return new FieldError( + typeof isValid === 'string' ? isValid : 'custom', + { + ...context, + hasLabel: false, + setting: customValidation, + }, + 'custom', + ); + } catch (err: any) { + throw new ProcessorError(err.message || err, context, 'validate:validateCustom'); + } +}; export const validateCustomInfo: ProcessorInfo = { - name: 'validateCustom', - process: validateCustom, - processSync: validateCustomSync, - shouldProcess: shouldValidate + name: 'validateCustom', + process: validateCustom, + processSync: validateCustomSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateDate.ts b/src/process/validation/rules/validateDate.ts index 0a14ccc9..ecea692d 100644 --- a/src/process/validation/rules/validateDate.ts +++ b/src/process/validation/rules/validateDate.ts @@ -1,52 +1,52 @@ import { FieldError } from 'error'; -import { DateTimeComponent, TextFieldComponent, RuleFn, RuleFnSync, ValidationContext } from 'types'; +import { DateTimeComponent, RuleFn, RuleFnSync, ValidationContext } from 'types'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableDateTimeComponent = (obj: any): obj is DateTimeComponent => { - return !!obj && !!obj.type && obj.type === 'datetime'; + return !!obj && !!obj.type && obj.type === 'datetime'; }; const isValidatable = (component: any) => { - return isValidatableDateTimeComponent(component); + return isValidatableDateTimeComponent(component); }; export const shouldValidate = (context: ValidationContext) => { - const { component, value} = context; - if (!value || !isValidatable(component)) { - return false; - } - return true; + const { component, value } = context; + if (!value || !isValidatable(component)) { + return false; + } + return true; }; export const validateDate: RuleFn = async (context: ValidationContext) => { - return validateDateSync(context); + return validateDateSync(context); }; export const validateDateSync: RuleFnSync = (context: ValidationContext) => { - const error = new FieldError('invalidDate', context, 'date'); - const { component, value} = context; - if (!shouldValidate(context)) { - return null; - } + const error = new FieldError('invalidDate', context, 'date'); + const { value } = context; + if (!shouldValidate(context)) { + return null; + } - // TODO: is this right? - if (typeof value === 'string') { - if (value.toLowerCase() === 'invalid date') { - return error; - } - if (new Date(value).toString() === 'Invalid Date') { - return error; - } - return null; - } else if (value instanceof Date) { - return value.toString() !== 'Invalid Date' ? null : error; + // TODO: is this right? + if (typeof value === 'string') { + if (value.toLowerCase() === 'invalid date') { + return error; + } + if (new Date(value).toString() === 'Invalid Date') { + return error; } - return error; + return null; + } else if (value instanceof Date) { + return value.toString() !== 'Invalid Date' ? null : error; + } + return error; }; export const validateDateInfo: ProcessorInfo = { - name: 'validateDate', - process: validateDate, - processSync: validateDateSync, - shouldProcess: shouldValidate + name: 'validateDate', + process: validateDate, + processSync: validateDateSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateDay.ts b/src/process/validation/rules/validateDay.ts index 4f277862..948e1899 100644 --- a/src/process/validation/rules/validateDay.ts +++ b/src/process/validation/rules/validateDay.ts @@ -3,107 +3,106 @@ import { DayComponent, RuleFn, RuleFnSync, ValidationContext } from 'types'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isLeapYear = (year: number) => { - // Year is leap if it is evenly divisible by 400 or evenly divisible by 4 and not evenly divisible by 100. - return !(year % 400) || (!!(year % 100) && !(year % 4)); + // Year is leap if it is evenly divisible by 400 or evenly divisible by 4 and not evenly divisible by 100. + return !(year % 400) || (!!(year % 100) && !(year % 4)); }; const getDaysInMonthCount = (month: number, year: number) => { - switch (month) { - case 1: // January - case 3: // March - case 5: // May - case 7: // July - case 8: // August - case 10: // October - case 12: // December - return 31; - case 4: // April - case 6: // June - case 9: // September - case 11: // November - return 30; - case 2: // February - return isLeapYear(year) ? 29 : 28; - default: - return 31; - } + switch (month) { + case 1: // January + case 3: // March + case 5: // May + case 7: // July + case 8: // August + case 10: // October + case 12: // December + return 31; + case 4: // April + case 6: // June + case 9: // September + case 11: // November + return 30; + case 2: // February + return isLeapYear(year) ? 29 : 28; + default: + return 31; + } }; const isDayComponent = (component: any): component is DayComponent => { - return component && component.type === 'day'; + return component && component.type === 'day'; }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!value) { - return false; - } - if (!isDayComponent(component)) { - return false; - } - return true; + const { component, value } = context; + if (!value) { + return false; + } + if (!isDayComponent(component)) { + return false; + } + return true; }; export const validateDay: RuleFn = async (context: ValidationContext) => { - return validateDaySync(context); + return validateDaySync(context); }; export const validateDaySync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context) || !isDayComponent(component)) { - return null; - } - const error = new FieldError('invalidDay', context, 'day'); - if (typeof value !== 'string') { - return error; - } - let [DAY, MONTH, YEAR] = component.dayFirst ? [0, 1, 2] : [1, 0, 2]; - - const values = value.split('/').map((x) => parseInt(x, 10)); - let day = values[DAY]; - let month = values[MONTH]; - let year = values[YEAR]; - - if (values.length !== 3) { - if (component.fields.day.hide) { - MONTH = MONTH === 0 ? 0 : MONTH - 1; - YEAR = YEAR - 1; - day = 0; - month = values[MONTH]; - year = values[YEAR]; + const { component, value } = context; + if (!shouldValidate(context) || !isDayComponent(component)) { + return null; + } + const error = new FieldError('invalidDay', context, 'day'); + if (typeof value !== 'string') { + return error; + } + let [DAY, MONTH, YEAR] = component.dayFirst ? [0, 1, 2] : [1, 0, 2]; - }; - if (component.fields.month.hide) { - DAY = DAY === 0 ? 0 : DAY - 1; - YEAR = YEAR - 1; - day = (component.fields.day.hide && day === 0) ? 0 : values[DAY]; - month = 0; - year = values[YEAR]; - }; - if (component.fields.year.hide) { - day = (component.fields.day.hide && day === 0) ? 0 : values[DAY]; - month = (component.fields.month.hide && month === 0) ? 0 :values[MONTH]; - year = 0; - }; - } + const values = value.split('/').map((x) => parseInt(x, 10)); + let day = values[DAY]; + let month = values[MONTH]; + let year = values[YEAR]; - const maxDay = getDaysInMonthCount(month, year); - - if (isNaN(day) || day < 0 || day > maxDay) { - return error; + if (values.length !== 3) { + if (component.fields.day.hide) { + MONTH = MONTH === 0 ? 0 : MONTH - 1; + YEAR = YEAR - 1; + day = 0; + month = values[MONTH]; + year = values[YEAR]; } - if (isNaN(month) || month < 0 || month > 12) { - return error; + if (component.fields.month.hide) { + DAY = DAY === 0 ? 0 : DAY - 1; + YEAR = YEAR - 1; + day = component.fields.day.hide && day === 0 ? 0 : values[DAY]; + month = 0; + year = values[YEAR]; } - if (isNaN(year) || year < 0 || year > 9999) { - return error; + if (component.fields.year.hide) { + day = component.fields.day.hide && day === 0 ? 0 : values[DAY]; + month = component.fields.month.hide && month === 0 ? 0 : values[MONTH]; + year = 0; } - return null; + } + + const maxDay = getDaysInMonthCount(month, year); + + if (isNaN(day) || day < 0 || day > maxDay) { + return error; + } + if (isNaN(month) || month < 0 || month > 12) { + return error; + } + if (isNaN(year) || year < 0 || year > 9999) { + return error; + } + return null; }; export const validateDayInfo: ProcessorInfo = { - name: 'validateDay', - process: validateDay, - processSync: validateDaySync, - shouldProcess: shouldValidate + name: 'validateDay', + process: validateDay, + processSync: validateDaySync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateEmail.ts b/src/process/validation/rules/validateEmail.ts index f5b23dcb..efd21cb6 100644 --- a/src/process/validation/rules/validateEmail.ts +++ b/src/process/validation/rules/validateEmail.ts @@ -3,45 +3,45 @@ import { EmailComponent, RuleFn, RuleFnSync, ValidationContext } from 'types'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableEmailComponent = (component: any): component is EmailComponent => { - return component && component.type === 'email'; + return component && component.type === 'email'; }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!value) { - return false; - } - if (!isValidatableEmailComponent(component)) { - return false; - } - return true; + const { component, value } = context; + if (!value) { + return false; + } + if (!isValidatableEmailComponent(component)) { + return false; + } + return true; }; export const validateEmail: RuleFn = async (context: ValidationContext) => { - return validateEmailSync(context); + return validateEmailSync(context); }; export const validateEmailSync: RuleFnSync = (context: ValidationContext) => { - const error = new FieldError('invalid_email', context, 'email'); - const { value } = context; - if (!shouldValidate(context)) { - return null; - } + const error = new FieldError('invalid_email', context, 'email'); + const { value } = context; + if (!shouldValidate(context)) { + return null; + } - // From http://stackoverflow.com/questions/46155/validate-email-address-in-javascript - const emailRegex = - /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + // From http://stackoverflow.com/questions/46155/validate-email-address-in-javascript + const emailRegex = + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - // Allow emails to be valid if the component is pristine and no value is provided. - if (typeof value === 'string' && !emailRegex.test(value)) { - return error; - } - return null; + // Allow emails to be valid if the component is pristine and no value is provided. + if (typeof value === 'string' && !emailRegex.test(value)) { + return error; + } + return null; }; export const validateEmailInfo: ProcessorInfo = { - name: 'validateEmail', - process: validateEmail, - processSync: validateEmailSync, - shouldProcess: shouldValidate + name: 'validateEmail', + process: validateEmail, + processSync: validateEmailSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateJson.ts b/src/process/validation/rules/validateJson.ts index a9b83ab8..3ee2069e 100644 --- a/src/process/validation/rules/validateJson.ts +++ b/src/process/validation/rules/validateJson.ts @@ -5,48 +5,52 @@ import { ProcessorInfo } from 'types/process/ProcessorInfo'; import { isObject } from 'lodash'; export const shouldValidate = (context: ValidationContext) => { - const { component } = context; - if (!component.validate?.json || !isObject(component.validate.json)) { - return false; - } - return true; + const { component } = context; + if (!component.validate?.json || !isObject(component.validate.json)) { + return false; + } + return true; }; export const validateJson: RuleFn = async (context: ValidationContext) => { - return validateJsonSync(context); + return validateJsonSync(context); }; export const validateJsonSync: RuleFnSync = (context: ValidationContext) => { - const { component, data, value, evalContext } = context; - if (!shouldValidate(context)) { - return null; - } + const { component, value, evalContext } = context; + if (!shouldValidate(context)) { + return null; + } - const func = component?.validate?.json; - const evalContextValue = evalContext ? evalContext(context) : context; - evalContextValue.value = value || null; - const valid: true | string = JSONLogicEvaluator.evaluate( - func, + const func = component?.validate?.json; + const evalContextValue = evalContext ? evalContext(context) : context; + evalContextValue.value = value || null; + const valid: true | string = JSONLogicEvaluator.evaluate( + func, + { + ...evalContextValue, + input: value, + }, + 'valid', + ); + if (valid === null) { + return null; + } + return valid === true + ? null + : new FieldError( + valid || 'jsonLogic', { - ...evalContextValue, - input: value, + ...context, + setting: func, }, - 'valid' - ); - if (valid === null) { - return null; - } - return valid === true - ? null - : new FieldError(valid || 'jsonLogic', { - ...context, - setting: func, - }, 'json'); + 'json', + ); }; export const validateJsonInfo: ProcessorInfo = { - name: 'validateJson', - process: validateJson, - processSync: validateJsonSync, - shouldProcess: shouldValidate, + name: 'validateJson', + process: validateJson, + processSync: validateJsonSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateMask.ts b/src/process/validation/rules/validateMask.ts index c56e11a0..f31fe551 100644 --- a/src/process/validation/rules/validateMask.ts +++ b/src/process/validation/rules/validateMask.ts @@ -5,156 +5,158 @@ import { ProcessorInfo } from 'types/process/ProcessorInfo'; import InputMask from 'inputmask'; const isMaskType = (obj: any): obj is DataObject & { maskName: string; value: string } => { - return ( - obj?.maskName && - typeof obj?.maskName === 'string' && - obj?.value && - typeof obj?.value === 'string' - ); + return ( + obj?.maskName && + typeof obj?.maskName === 'string' && + obj?.value && + typeof obj?.value === 'string' + ); }; const isValidatableComponent = (component: any, instance: any): component is TextFieldComponent => { - if (!component) return false; + if (!component) return false; - const { type, inputMask, inputMasks, validate } = component; + const { type, inputMask, inputMasks, validate } = component; - // For some reason we skip mask validation for time components - if (type === 'time') return false; + // For some reason we skip mask validation for time components + if (type === 'time') return false; - const hasInputMask = inputMask || !isEmpty(inputMasks); - // Include instance.skipMaskValidation check to maintain backward compatibility - const skipMaskValidation = validate?.skipMaskValidation || instance?.skipMaskValidation; + const hasInputMask = inputMask || !isEmpty(inputMasks); + // Include instance.skipMaskValidation check to maintain backward compatibility + const skipMaskValidation = validate?.skipMaskValidation || instance?.skipMaskValidation; - return hasInputMask && !skipMaskValidation; + return hasInputMask && !skipMaskValidation; }; function getMaskByLabel(component: TextFieldComponent, maskName: string | undefined) { - if (maskName) { - const inputMask = component.inputMasks?.find((inputMask) => { - return inputMask.label === maskName; - }); - return inputMask ? inputMask.mask : undefined; - } - return; + if (maskName) { + const inputMask = component.inputMasks?.find((inputMask) => { + return inputMask.label === maskName; + }); + return inputMask ? inputMask.mask : undefined; + } + return; } function getInputMask(mask: string | string[], placeholderChar?: string) { - if (mask instanceof Array) { - return mask; - } - const maskArray: (string | RegExp)[] = []; - for (let i = 0; i < mask.length; i++) { - switch (mask[i]) { - case '9': - maskArray.push(/\d/); - break; - case 'A': - maskArray.push(/[a-zA-Z]/); - break; - case 'a': - maskArray.push(/[a-z]/); - break; - case '*': - maskArray.push(/[a-zA-Z0-9]/); - break; - // If char which is used inside mask placeholder was used in the mask, replace it with space to prevent errors - case placeholderChar: - maskArray.push(' '); - break; - default: - maskArray.push(mask[i]); - break; - } + if (mask instanceof Array) { + return mask; + } + const maskArray: (string | RegExp)[] = []; + for (let i = 0; i < mask.length; i++) { + switch (mask[i]) { + case '9': + maskArray.push(/\d/); + break; + case 'A': + maskArray.push(/[a-zA-Z]/); + break; + case 'a': + maskArray.push(/[a-z]/); + break; + case '*': + maskArray.push(/[a-zA-Z0-9]/); + break; + // If char which is used inside mask placeholder was used in the mask, replace it with space to prevent errors + case placeholderChar: + maskArray.push(' '); + break; + default: + maskArray.push(mask[i]); + break; } - return maskArray; + } + return maskArray; } export function matchInputMask(value: any, inputMask: any) { - if (!inputMask) { - return true; - } + if (!inputMask) { + return true; + } - // If value is longer than mask, it isn't valid. - if (value.length > inputMask.length) { - return false; - } + // If value is longer than mask, it isn't valid. + if (value.length > inputMask.length) { + return false; + } + + for (let i = 0; i < inputMask.length; i++) { + const char = value[i]; + const charPart = inputMask[i]; - for (let i = 0; i < inputMask.length; i++) { - const char = value[i]; - const charPart = inputMask[i]; - - if (charPart instanceof RegExp) { - if (!charPart.test(char)) { - return false; - } - continue; - } else if (charPart !== char) { - return false; - } + if (charPart instanceof RegExp) { + if (!charPart.test(char)) { + return false; + } + continue; + } else if (charPart !== char) { + return false; } + } - return true; + return true; } export const shouldValidate = (context: ValidationContext) => { - const { component, value, instance } = context; - if (!isValidatableComponent(component, instance) || !value) { - return false; + const { component, value, instance } = context; + if (!isValidatableComponent(component, instance) || !value) { + return false; + } + if (value == null) { + return false; + } + if (component.allowMultipleMasks && (component as TextFieldComponent).inputMasks?.length) { + const mask = value && isMaskType(value) ? value : undefined; + const formioInputMask = getMaskByLabel(component as TextFieldComponent, mask?.maskName); + if (formioInputMask && !getInputMask(formioInputMask)) { + return false; } - if (value == null) { - return false; - } - if (component.allowMultipleMasks && (component as TextFieldComponent).inputMasks?.length) { - const mask = value && isMaskType(value) ? value : undefined; - const formioInputMask = getMaskByLabel(component as TextFieldComponent, mask?.maskName); - if (formioInputMask && !getInputMask(formioInputMask)) { - return false; - } - } else if (!getInputMask((component as TextFieldComponent).inputMask || '')) { - return false; - } - return true; + } else if (!getInputMask((component as TextFieldComponent).inputMask || '')) { + return false; + } + return true; }; export const validateMask: RuleFn = async (context: ValidationContext) => { - return validateMaskSync(context); + return validateMaskSync(context); }; // TODO: this function has side effects export const validateMaskSync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - let inputMask: string | string[] | undefined; - let maskValue: string | undefined; - if (component.allowMultipleMasks && (component as TextFieldComponent).inputMasks?.length) { - const mask = value && isMaskType(value) ? value : undefined; - const formioInputMask = getMaskByLabel(component as TextFieldComponent, mask?.maskName); - if (formioInputMask) { - inputMask = formioInputMask; - } - maskValue = mask?.value; - } else { - inputMask = (component as TextFieldComponent).inputMask || ''; - } - if (!inputMask) { - return null; - } - if (value && inputMask && typeof value === 'string' && component.type === 'textfield') { - return InputMask.isValid(value, {mask: inputMask.toString()}) ? null : new FieldError('mask', context); - } - let inputMaskArr = getInputMask(inputMask); - if (value != null && inputMaskArr) { - const error = new FieldError('mask', context); - return matchInputMask(maskValue || value, inputMaskArr) ? null : error; + const { component, value } = context; + if (!shouldValidate(context)) { + return null; + } + let inputMask: string | string[] | undefined; + let maskValue: string | undefined; + if (component.allowMultipleMasks && (component as TextFieldComponent).inputMasks?.length) { + const mask = value && isMaskType(value) ? value : undefined; + const formioInputMask = getMaskByLabel(component as TextFieldComponent, mask?.maskName); + if (formioInputMask) { + inputMask = formioInputMask; } + maskValue = mask?.value; + } else { + inputMask = (component as TextFieldComponent).inputMask || ''; + } + if (!inputMask) { return null; + } + if (value && inputMask && typeof value === 'string' && component.type === 'textfield') { + return InputMask.isValid(value, { mask: inputMask.toString() }) + ? null + : new FieldError('mask', context); + } + const inputMaskArr = getInputMask(inputMask); + if (value != null && inputMaskArr) { + const error = new FieldError('mask', context); + return matchInputMask(maskValue || value, inputMaskArr) ? null : error; + } + return null; }; export const validateMaskInfo: ProcessorInfo = { - name: 'validateMask', - process: validateMask, - processSync: validateMaskSync, - shouldProcess: shouldValidate, + name: 'validateMask', + process: validateMask, + processSync: validateMaskSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateMaximumDay.ts b/src/process/validation/rules/validateMaximumDay.ts index bc55280d..e0fdc978 100644 --- a/src/process/validation/rules/validateMaximumDay.ts +++ b/src/process/validation/rules/validateMaximumDay.ts @@ -4,52 +4,60 @@ import { dayjs, isPartialDay, getDateValidationFormat, getDateSetting } from 'ut import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableDayComponent = (component: any): component is DayComponent => { - return component && component.type === 'day' && component.hasOwnProperty('maxDate'); + return component && component.type === 'day' && component.hasOwnProperty('maxDate'); }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isValidatableDayComponent(component)) { - return false; - } - if (isPartialDay(component, value as (string | undefined))) { - return false; - } - if (!getDateSetting((component as DayComponent).maxDate)) { - return false; - } - return true; + const { component, value } = context; + if (!isValidatableDayComponent(component)) { + return false; + } + if (isPartialDay(component, value as string | undefined)) { + return false; + } + if (!getDateSetting((component as DayComponent).maxDate)) { + return false; + } + return true; }; export const validateMaximumDay: RuleFn = async (context: ValidationContext) => { - return validateMaximumDaySync(context); + return validateMaximumDaySync(context); }; export const validateMaximumDaySync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - if (typeof value !== 'string') { - throw new ProcessorError(`Cannot validate day value ${value} because it is not a string`, context, 'validate:validateMaximumDay'); - } - // TODO: this validation probably goes for dates and days - const format = getDateValidationFormat(component as DayComponent); - const date = dayjs(value, format); - const maxDate = getDateSetting((component as DayComponent).maxDate); + const { component, value } = context; + if (!shouldValidate(context)) { + return null; + } + if (typeof value !== 'string') { + throw new ProcessorError( + `Cannot validate day value ${value} because it is not a string`, + context, + 'validate:validateMaximumDay', + ); + } + // TODO: this validation probably goes for dates and days + const format = getDateValidationFormat(component as DayComponent); + const date = dayjs(value, format); + const maxDate = getDateSetting((component as DayComponent).maxDate); - if (maxDate === null) { - return null; - } else { - maxDate.setHours(0, 0, 0, 0); - } - const error = new FieldError('maxDay', { ...context, maxDate: String(maxDate), setting: String(maxDate) }); - return date.isBefore(dayjs(maxDate)) || date.isSame(dayjs(maxDate)) ? null : error; + if (maxDate === null) { + return null; + } else { + maxDate.setHours(0, 0, 0, 0); + } + const error = new FieldError('maxDay', { + ...context, + maxDate: String(maxDate), + setting: String(maxDate), + }); + return date.isBefore(dayjs(maxDate)) || date.isSame(dayjs(maxDate)) ? null : error; }; export const validateMaximumDayInfo: ProcessorInfo = { - name: 'validateMaximumDay', - process: validateMaximumDay, - processSync: validateMaximumDaySync, - shouldProcess: shouldValidate, + name: 'validateMaximumDay', + process: validateMaximumDay, + processSync: validateMaximumDaySync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateMaximumLength.ts b/src/process/validation/rules/validateMaximumLength.ts index b7f3d20d..4f73020d 100644 --- a/src/process/validation/rules/validateMaximumLength.ts +++ b/src/process/validation/rules/validateMaximumLength.ts @@ -3,62 +3,66 @@ import { TextFieldComponent, RuleFn, RuleFnSync, ValidationContext } from 'types import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableTextFieldComponent = (component: any): component is TextFieldComponent => { - return component && component.validate?.hasOwnProperty('maxLength'); + return component && component.validate?.hasOwnProperty('maxLength'); }; const getValidationSetting = (component: any) => { - let maxLength = (component as TextFieldComponent).validate?.maxLength; - maxLength = (typeof maxLength === 'string') ? parseInt(maxLength, 10) : maxLength; - return maxLength; + let maxLength = (component as TextFieldComponent).validate?.maxLength; + maxLength = typeof maxLength === 'string' ? parseInt(maxLength, 10) : maxLength; + return maxLength; }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isValidatableTextFieldComponent(component)) { - return false; - } - if (!value) { - return false; - } - if (typeof value !== 'string') { - return false; - } - const setting = getValidationSetting(component); - if (setting === undefined) { - return false; - } - if (!setting || Number.isNaN(setting)) { - return false; - } - return true; + const { component, value } = context; + if (!isValidatableTextFieldComponent(component)) { + return false; + } + if (!value) { + return false; + } + if (typeof value !== 'string') { + return false; + } + const setting = getValidationSetting(component); + if (setting === undefined) { + return false; + } + if (!setting || Number.isNaN(setting)) { + return false; + } + return true; }; export const validateMaximumLength: RuleFn = async (context: ValidationContext) => { - return validateMaximumLengthSync(context); + return validateMaximumLengthSync(context); }; export const validateMaximumLengthSync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - const maxLength = getValidationSetting(component); - if (maxLength === undefined || Number.isNaN(maxLength)) { - return null; - } - if (!value || typeof value !== 'string') { - return null; - } - if (value.length > maxLength) { - const error = new FieldError('maxLength', { ...context, length: String(maxLength), setting: String(maxLength) }); - return error; - } + const { component, value } = context; + if (!shouldValidate(context)) { return null; -} + } + const maxLength = getValidationSetting(component); + if (maxLength === undefined || Number.isNaN(maxLength)) { + return null; + } + if (!value || typeof value !== 'string') { + return null; + } + if (value.length > maxLength) { + const error = new FieldError('maxLength', { + ...context, + length: String(maxLength), + setting: String(maxLength), + }); + return error; + } + return null; +}; export const validateMaximumLengthInfo: ProcessorInfo = { - name: 'validateMaximumLength', - process: validateMaximumLength, - processSync: validateMaximumLengthSync, - shouldProcess: shouldValidate, + name: 'validateMaximumLength', + process: validateMaximumLength, + processSync: validateMaximumLengthSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateMaximumSelectedCount.ts b/src/process/validation/rules/validateMaximumSelectedCount.ts index d093dfe3..7cdfb656 100644 --- a/src/process/validation/rules/validateMaximumSelectedCount.ts +++ b/src/process/validation/rules/validateMaximumSelectedCount.ts @@ -3,86 +3,92 @@ import { SelectBoxesComponent, DataObject, RuleFn, RuleFnSync, ValidationContext import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableSelectBoxesComponent = (component: any): component is SelectBoxesComponent => { - return component && component.validate?.hasOwnProperty('maxSelectedCount'); + return component && component.validate?.hasOwnProperty('maxSelectedCount'); }; const getValidationSetting = (component: SelectBoxesComponent) => { - let max = (component as SelectBoxesComponent).validate?.maxSelectedCount; - if (typeof max === 'string') { - max = parseFloat(max); - } - return max; -} + let max = (component as SelectBoxesComponent).validate?.maxSelectedCount; + if (typeof max === 'string') { + max = parseFloat(max); + } + return max; +}; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isValidatableSelectBoxesComponent(component)) { - return false; - } - if (!value) { - return false; - } - if (!getValidationSetting(component)) { - return false; - } - return true; + const { component, value } = context; + if (!isValidatableSelectBoxesComponent(component)) { + return false; + } + if (!value) { + return false; + } + if (!getValidationSetting(component)) { + return false; + } + return true; }; -function validateValue(value: DataObject[any], context: ValidationContext): asserts value is Record { - if (value == null || typeof value !== 'object') { - throw new ProcessorError( - `Cannot validate maximum selected count for value ${value} as it is not an object`, - context, - 'validate:validateMaximumSelectedCount' - ); - } - const subValues = Object.values(value); - if (!subValues.every((value) => typeof value === 'boolean')) { - throw new ProcessorError( - `Cannot validate maximum selected count for value ${value} because it has non-boolean members`, - context, - 'validate:validateMaximumSelectedCount' - ); - } +function validateValue( + value: DataObject[any], + context: ValidationContext, +): asserts value is Record { + if (value == null || typeof value !== 'object') { + throw new ProcessorError( + `Cannot validate maximum selected count for value ${value} as it is not an object`, + context, + 'validate:validateMaximumSelectedCount', + ); + } + const subValues = Object.values(value); + if (!subValues.every((value) => typeof value === 'boolean')) { + throw new ProcessorError( + `Cannot validate maximum selected count for value ${value} because it has non-boolean members`, + context, + 'validate:validateMaximumSelectedCount', + ); + } } export const validateMaximumSelectedCount: RuleFn = async (context: ValidationContext) => { - return validateMaximumSelectedCountSync(context); + return validateMaximumSelectedCountSync(context); }; export const validateMaximumSelectedCountSync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - try { - - if (!shouldValidate(context)) { - return null; - } - validateValue(value, context); - const max = getValidationSetting(component as SelectBoxesComponent); - if (!max) { - return null; - } - const count = Object.keys(value).reduce((sum, key) => (value[key] ? ++sum : sum), 0); + const { component, value } = context; + try { + if (!shouldValidate(context)) { + return null; + } + validateValue(value, context); + const max = getValidationSetting(component as SelectBoxesComponent); + if (!max) { + return null; + } + const count = Object.keys(value).reduce((sum, key) => (value[key] ? ++sum : sum), 0); - // Should not be triggered if there is no options selected at all - if (count <= 0) { - return null; - } - return count > max - ? new FieldError((component as SelectBoxesComponent).maxSelectedCountMessage || 'maxSelectedCount', { - ...context, - maxCount: String(max), - setting: String(max), - }) - : null; - } catch (err: any) { - throw new ProcessorError(err.message || err, context, 'validate:validateMaximumSelectedCount'); + // Should not be triggered if there is no options selected at all + if (count <= 0) { + return null; } -} + return count > max + ? new FieldError( + (component as SelectBoxesComponent).maxSelectedCountMessage || 'maxSelectedCount', + { + ...context, + maxCount: String(max), + setting: String(max), + }, + ) + : null; + } catch (err: any) { + throw new ProcessorError(err.message || err, context, 'validate:validateMaximumSelectedCount'); + } +}; -export const validateMaximumSelectedCountInfo: ProcessorInfo = { +export const validateMaximumSelectedCountInfo: ProcessorInfo = + { name: 'validateMaximumSelectedCount', process: validateMaximumSelectedCount, processSync: validateMaximumSelectedCountSync, shouldProcess: shouldValidate, -}; + }; diff --git a/src/process/validation/rules/validateMaximumValue.ts b/src/process/validation/rules/validateMaximumValue.ts index 8fc279c7..6f46bf44 100644 --- a/src/process/validation/rules/validateMaximumValue.ts +++ b/src/process/validation/rules/validateMaximumValue.ts @@ -3,61 +3,61 @@ import { NumberComponent, RuleFn, RuleFnSync, ValidationContext } from 'types'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableNumberComponent = (component: any): component is NumberComponent => { - return component && component.validate?.hasOwnProperty('max'); + return component && component.validate?.hasOwnProperty('max'); }; const getValidationSetting = (component: any) => { - let max = (component as NumberComponent).validate?.max; - if (typeof max === 'string') { - max = parseFloat(max); - } - return max; + let max = (component as NumberComponent).validate?.max; + if (typeof max === 'string') { + max = parseFloat(max); + } + return max; }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isValidatableNumberComponent(component)) { - return false; - } - if (value === null) { - return false; - } - if (Number.isNaN(getValidationSetting(component))) { - return false; - } - return true; + const { component, value } = context; + if (!isValidatableNumberComponent(component)) { + return false; + } + if (value === null) { + return false; + } + if (Number.isNaN(getValidationSetting(component))) { + return false; + } + return true; }; export const validateMaximumValue: RuleFn = async (context: ValidationContext) => { - return validateMaximumValueSync(context); + return validateMaximumValueSync(context); }; export const validateMaximumValueSync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - const max = getValidationSetting(component); - if (max === undefined || Number.isNaN(max)) { - return null; - } - const parsedValue = typeof value === 'string' ? parseFloat(value) : Number(value); - if (Number.isNaN(parsedValue)) { - throw new ProcessorError( - `Cannot validate value ${parsedValue} because it is invalid`, - context, - 'validate:validateMaximumValue' - ); - } + const { component, value } = context; + if (!shouldValidate(context)) { + return null; + } + const max = getValidationSetting(component); + if (max === undefined || Number.isNaN(max)) { + return null; + } + const parsedValue = typeof value === 'string' ? parseFloat(value) : Number(value); + if (Number.isNaN(parsedValue)) { + throw new ProcessorError( + `Cannot validate value ${parsedValue} because it is invalid`, + context, + 'validate:validateMaximumValue', + ); + } - return parsedValue <= max - ? null - : new FieldError('max', {...context, max: String(max), setting: String(max) }); + return parsedValue <= max + ? null + : new FieldError('max', { ...context, max: String(max), setting: String(max) }); }; export const validateMaximumValueInfo: ProcessorInfo = { - name: 'validateMaximumValue', - process: validateMaximumValue, - processSync: validateMaximumValueSync, - shouldProcess: shouldValidate, + name: 'validateMaximumValue', + process: validateMaximumValue, + processSync: validateMaximumValueSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateMaximumWords.ts b/src/process/validation/rules/validateMaximumWords.ts index ef152b86..d36f8080 100644 --- a/src/process/validation/rules/validateMaximumWords.ts +++ b/src/process/validation/rules/validateMaximumWords.ts @@ -3,54 +3,58 @@ import { TextFieldComponent, RuleFn, RuleFnSync, ValidationContext } from 'types import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableTextFieldComponent = (component: any): component is TextFieldComponent => { - return component && component.validate?.hasOwnProperty('maxWords'); + return component && component.validate?.hasOwnProperty('maxWords'); }; const getValidationSetting = (component: any) => { - let maxWords = (component as TextFieldComponent).validate?.maxWords; - if (typeof maxWords === 'string') { - maxWords = parseInt(maxWords, 10); - } - return maxWords; + let maxWords = (component as TextFieldComponent).validate?.maxWords; + if (typeof maxWords === 'string') { + maxWords = parseInt(maxWords, 10); + } + return maxWords; }; const shouldValidate = (context: ValidationContext) => { - const { component } = context; - if (!isValidatableTextFieldComponent(component)) { - return false; - } - const setting = getValidationSetting(component); - if (setting === undefined) { - return false; - } - if (!setting || Number.isNaN(setting)) { - return false; - } - return true; -} + const { component } = context; + if (!isValidatableTextFieldComponent(component)) { + return false; + } + const setting = getValidationSetting(component); + if (setting === undefined) { + return false; + } + if (!setting || Number.isNaN(setting)) { + return false; + } + return true; +}; export const validateMaximumWords: RuleFn = async (context: ValidationContext) => { - return validateMaximumWordsSync(context); + return validateMaximumWordsSync(context); }; export const validateMaximumWordsSync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - const maxWords = getValidationSetting(component); - if (maxWords && typeof value === 'string') { - if (value.trim().split(/\s+/).length > maxWords) { - const error = new FieldError('maxWords', { ...context, length: String(maxWords), setting: String(maxWords) }); - return error; - } - } + const { component, value } = context; + if (!shouldValidate(context)) { return null; + } + const maxWords = getValidationSetting(component); + if (maxWords && typeof value === 'string') { + if (value.trim().split(/\s+/).length > maxWords) { + const error = new FieldError('maxWords', { + ...context, + length: String(maxWords), + setting: String(maxWords), + }); + return error; + } + } + return null; }; export const validateMaximumWordsInfo: ProcessorInfo = { - name: 'validateMaximumWords', - process: validateMaximumWords, - processSync: validateMaximumWordsSync, - shouldProcess: shouldValidate, + name: 'validateMaximumWords', + process: validateMaximumWords, + processSync: validateMaximumWordsSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateMaximumYear.ts b/src/process/validation/rules/validateMaximumYear.ts index 08aec9a3..75b1e4c7 100644 --- a/src/process/validation/rules/validateMaximumYear.ts +++ b/src/process/validation/rules/validateMaximumYear.ts @@ -4,63 +4,68 @@ import { RuleFn, RuleFnSync, ValidationContext } from 'types'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableDayComponent = (component: any): component is DayComponent => { - return ( - component && - component.type === 'day' && - (component.hasOwnProperty('maxYear') || component.fields?.year?.hasOwnProperty('maxYear')) - ); + return ( + component && + component.type === 'day' && + (component.hasOwnProperty('maxYear') || component.fields?.year?.hasOwnProperty('maxYear')) + ); }; export const shouldValidate = (context: ValidationContext) => { - const { component } = context; - if (!isValidatableDayComponent(component)) { - return false; - } - if (!(component as DayComponent).maxYear && !(component as DayComponent).fields.year.maxYear) { - return false; - } - return true; -} + const { component } = context; + if (!isValidatableDayComponent(component)) { + return false; + } + if (!(component as DayComponent).maxYear && !(component as DayComponent).fields.year.maxYear) { + return false; + } + return true; +}; export const validateMaximumYear: RuleFn = async (context: ValidationContext) => { - return validateMaximumYearSync(context); + return validateMaximumYearSync(context); }; export const validateMaximumYearSync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - if (typeof value !== 'string' && typeof value !== 'number') { - throw new ProcessorError(`Cannot validate maximum year for value ${value}`, context, 'validate:validateMaximumYear'); - } - const testValue = typeof value === 'string' ? value : String(value); - const testArr = /\d{4}$/.exec(testValue); - const year = testArr ? testArr[0] : null; - if ( - (component as DayComponent).maxYear && - (component as DayComponent).fields?.year?.maxYear && - (component as DayComponent).maxYear !== (component as DayComponent).fields.year.maxYear - ) { - throw new ProcessorError( - 'Cannot validate maximum year, component.maxYear and component.fields.year.maxYear are not equal', - context, - 'validate:validateMaximumYear' - ); - } - const maxYear = (component as DayComponent).maxYear || (component as DayComponent).fields.year.maxYear; - if (!maxYear || !year) { - return null; - } + const { component, value } = context; + if (!shouldValidate(context)) { + return null; + } + if (typeof value !== 'string' && typeof value !== 'number') { + throw new ProcessorError( + `Cannot validate maximum year for value ${value}`, + context, + 'validate:validateMaximumYear', + ); + } + const testValue = typeof value === 'string' ? value : String(value); + const testArr = /\d{4}$/.exec(testValue); + const year = testArr ? testArr[0] : null; + if ( + (component as DayComponent).maxYear && + (component as DayComponent).fields?.year?.maxYear && + (component as DayComponent).maxYear !== (component as DayComponent).fields.year.maxYear + ) { + throw new ProcessorError( + 'Cannot validate maximum year, component.maxYear and component.fields.year.maxYear are not equal', + context, + 'validate:validateMaximumYear', + ); + } + const maxYear = + (component as DayComponent).maxYear || (component as DayComponent).fields.year.maxYear; + if (!maxYear || !year) { + return null; + } - return +year <= +maxYear - ? null - : new FieldError('maxYear', {...context, maxYear: String(maxYear), setting: String(maxYear) }); -} + return +year <= +maxYear + ? null + : new FieldError('maxYear', { ...context, maxYear: String(maxYear), setting: String(maxYear) }); +}; export const validateMaximumYearInfo: ProcessorInfo = { - name: 'validateMaximumYear', - process: validateMaximumYear, - processSync: validateMaximumYearSync, - shouldProcess: shouldValidate, + name: 'validateMaximumYear', + process: validateMaximumYear, + processSync: validateMaximumYearSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateMinimumDay.ts b/src/process/validation/rules/validateMinimumDay.ts index 5426b5fc..10aa3da0 100644 --- a/src/process/validation/rules/validateMinimumDay.ts +++ b/src/process/validation/rules/validateMinimumDay.ts @@ -4,53 +4,61 @@ import { dayjs, isPartialDay, getDateValidationFormat, getDateSetting } from 'ut import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableDayComponent = (component: any): component is DayComponent => { - return component && component.type === 'day' && component.hasOwnProperty('minDate'); + return component && component.type === 'day' && component.hasOwnProperty('minDate'); }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isValidatableDayComponent(component)) { - return false; - } - if (isPartialDay(component, value as (string | undefined))) { - return false; - } - if (getDateSetting((component as DayComponent).minDate) === null) { - return false; - } - return true; + const { component, value } = context; + if (!isValidatableDayComponent(component)) { + return false; + } + if (isPartialDay(component, value as string | undefined)) { + return false; + } + if (getDateSetting((component as DayComponent).minDate) === null) { + return false; + } + return true; }; export const validateMinimumDay: RuleFn = async (context: ValidationContext) => { - return validateMinimumDaySync(context); + return validateMinimumDaySync(context); }; export const validateMinimumDaySync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - if (typeof value !== 'string') { - throw new ProcessorError(`Cannot validate day value ${value} because it is not a string`, context, 'validate:validateMinimumDay'); - } + const { component, value } = context; + if (!shouldValidate(context)) { + return null; + } + if (typeof value !== 'string') { + throw new ProcessorError( + `Cannot validate day value ${value} because it is not a string`, + context, + 'validate:validateMinimumDay', + ); + } - const date = getDateValidationFormat((component as DayComponent)) - ? dayjs(value, getDateValidationFormat((component as DayComponent))) - : dayjs(value); - const minDate = getDateSetting((component as DayComponent).minDate); + const date = getDateValidationFormat(component as DayComponent) + ? dayjs(value, getDateValidationFormat(component as DayComponent)) + : dayjs(value); + const minDate = getDateSetting((component as DayComponent).minDate); - if (minDate === null) { - return null; - } else { - minDate.setHours(0, 0, 0, 0); - } - const error = new FieldError('minDay', { ...context, minDate: String(minDate), setting: String(minDate) }); - return date.isAfter(minDate) || date.isSame(minDate) ? null : error; + if (minDate === null) { + return null; + } else { + minDate.setHours(0, 0, 0, 0); + } + const error = new FieldError('minDay', { + ...context, + minDate: String(minDate), + setting: String(minDate), + }); + return date.isAfter(minDate) || date.isSame(minDate) ? null : error; }; export const validateMinimumDayInfo: ProcessorInfo = { - name: 'validateMinimumDay', - process: validateMinimumDay, - processSync: validateMinimumDaySync, - shouldProcess: shouldValidate, + name: 'validateMinimumDay', + process: validateMinimumDay, + processSync: validateMinimumDaySync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateMinimumLength.ts b/src/process/validation/rules/validateMinimumLength.ts index 4755bec8..5bfa6931 100644 --- a/src/process/validation/rules/validateMinimumLength.ts +++ b/src/process/validation/rules/validateMinimumLength.ts @@ -3,53 +3,57 @@ import { RuleFn, RuleFnSync, TextFieldComponent, ValidationContext } from 'types import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableTextFieldComponent = (component: any): component is TextFieldComponent => { - return component && component.validate?.hasOwnProperty('minLength'); + return component && component.validate?.hasOwnProperty('minLength'); }; const getValidationSetting = (component: TextFieldComponent) => { - let minLength = (component as TextFieldComponent).validate?.minLength; - if (typeof minLength === 'string') { - minLength = parseInt(minLength, 10); - } - return minLength; + let minLength = (component as TextFieldComponent).validate?.minLength; + if (typeof minLength === 'string') { + minLength = parseInt(minLength, 10); + } + return minLength; }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isValidatableTextFieldComponent(component) || !value) { - return false; - } - if (!value) { - return false; - } - if (!getValidationSetting(component)) { - return false; - } - return true; + const { component, value } = context; + if (!isValidatableTextFieldComponent(component) || !value) { + return false; + } + if (!value) { + return false; + } + if (!getValidationSetting(component)) { + return false; + } + return true; }; export const validateMinimumLength: RuleFn = async (context: ValidationContext) => { - return validateMinimumLengthSync(context); + return validateMinimumLengthSync(context); }; export const validateMinimumLengthSync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - const minLength = getValidationSetting(component as TextFieldComponent); - if (value && minLength && typeof value === 'string') { - if (value.length < minLength) { - const error = new FieldError('minLength', { ...context, length: String(minLength), setting: String(minLength) }); - return error; - } - } + const { component, value } = context; + if (!shouldValidate(context)) { return null; + } + const minLength = getValidationSetting(component as TextFieldComponent); + if (value && minLength && typeof value === 'string') { + if (value.length < minLength) { + const error = new FieldError('minLength', { + ...context, + length: String(minLength), + setting: String(minLength), + }); + return error; + } + } + return null; }; export const validateMinimumLengthInfo: ProcessorInfo = { - name: 'validateMinimumLength', - process: validateMinimumLength, - processSync: validateMinimumLengthSync, - shouldProcess: shouldValidate, + name: 'validateMinimumLength', + process: validateMinimumLength, + processSync: validateMinimumLengthSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateMinimumSelectedCount.ts b/src/process/validation/rules/validateMinimumSelectedCount.ts index 70efcf40..fa301cc7 100644 --- a/src/process/validation/rules/validateMinimumSelectedCount.ts +++ b/src/process/validation/rules/validateMinimumSelectedCount.ts @@ -3,86 +3,93 @@ import { SelectBoxesComponent, DataObject, RuleFn, RuleFnSync, ValidationContext import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableSelectBoxesComponent = (component: any): component is SelectBoxesComponent => { - return component && component.validate?.hasOwnProperty('minSelectedCount'); + return component && component.validate?.hasOwnProperty('minSelectedCount'); }; const getValidationSetting = (component: SelectBoxesComponent) => { - let min = (component as SelectBoxesComponent).validate?.minSelectedCount; - if (typeof min === 'string') { - min = parseFloat(min); - } - return min; + let min = (component as SelectBoxesComponent).validate?.minSelectedCount; + if (typeof min === 'string') { + min = parseFloat(min); + } + return min; }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isValidatableSelectBoxesComponent(component)) { - return false; - } - if (!value) { - return false; - } - if (!getValidationSetting(component)) { - return false; - } - return true; + const { component, value } = context; + if (!isValidatableSelectBoxesComponent(component)) { + return false; + } + if (!value) { + return false; + } + if (!getValidationSetting(component)) { + return false; + } + return true; }; -function validateValue(value: DataObject[any], context: ValidationContext): asserts value is Record { - if (value == null || typeof value !== 'object') { - throw new ProcessorError( - `Cannot validate maximum selected count for value ${value} as it is not an object`, - context, - 'validate:validateMinimumSelectedCount' - ); - } - const subValues = Object.values(value); - if (!subValues.every((value) => typeof value === 'boolean')) { - throw new ProcessorError( - `Cannot validate maximum selected count for value ${value} because it has non-boolean members`, - context, - 'validate:validateMinimumSelectedCount' - ); - } +function validateValue( + value: DataObject[any], + context: ValidationContext, +): asserts value is Record { + if (value == null || typeof value !== 'object') { + throw new ProcessorError( + `Cannot validate maximum selected count for value ${value} as it is not an object`, + context, + 'validate:validateMinimumSelectedCount', + ); + } + const subValues = Object.values(value); + if (!subValues.every((value) => typeof value === 'boolean')) { + throw new ProcessorError( + `Cannot validate maximum selected count for value ${value} because it has non-boolean members`, + context, + 'validate:validateMinimumSelectedCount', + ); + } } export const validateMinimumSelectedCount: RuleFn = async (context: ValidationContext) => { - return validateMinimumSelectedCountSync(context); + return validateMinimumSelectedCountSync(context); }; export const validateMinimumSelectedCountSync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - try { - - if (!shouldValidate(context)) { - return null; - } - validateValue(value, context); - const min = getValidationSetting((component as SelectBoxesComponent)); - if (!min) { - return null; - } - const count = Object.keys(value).reduce((sum, key) => (value[key] ? ++sum : sum), 0); + const { component, value } = context; + try { + if (!shouldValidate(context)) { + return null; + } + validateValue(value, context); + const min = getValidationSetting(component as SelectBoxesComponent); + if (!min) { + return null; + } + const count = Object.keys(value).reduce((sum, key) => (value[key] ? ++sum : sum), 0); - // Should not be triggered if there are no options selected at all - if (count <= 0) { - return null; - } - return count < min - ? new FieldError((component as SelectBoxesComponent).minSelectedCountMessage || 'minSelectedCount', { - ...context, - minCount: String(min), - setting: String(min), - }, 'minSelectedCount') - : null; - } catch (err: any) { - throw new ProcessorError(err.message || err, context, 'validate:validateMinimumSelectedCount'); + // Should not be triggered if there are no options selected at all + if (count <= 0) { + return null; } + return count < min + ? new FieldError( + (component as SelectBoxesComponent).minSelectedCountMessage || 'minSelectedCount', + { + ...context, + minCount: String(min), + setting: String(min), + }, + 'minSelectedCount', + ) + : null; + } catch (err: any) { + throw new ProcessorError(err.message || err, context, 'validate:validateMinimumSelectedCount'); + } }; -export const validateMinimumSelectedCountInfo: ProcessorInfo = { +export const validateMinimumSelectedCountInfo: ProcessorInfo = + { name: 'validateMinimumSelectedCount', process: validateMinimumSelectedCount, processSync: validateMinimumSelectedCountSync, shouldProcess: shouldValidate, -}; + }; diff --git a/src/process/validation/rules/validateMinimumValue.ts b/src/process/validation/rules/validateMinimumValue.ts index 79d41323..f888872f 100644 --- a/src/process/validation/rules/validateMinimumValue.ts +++ b/src/process/validation/rules/validateMinimumValue.ts @@ -3,61 +3,61 @@ import { NumberComponent, RuleFn, RuleFnSync, ValidationContext } from 'types'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableNumberComponent = (component: any): component is NumberComponent => { - return component && component.validate?.hasOwnProperty('min'); + return component && component.validate?.hasOwnProperty('min'); }; const getValidationSetting = (component: any) => { - let min = (component as NumberComponent).validate?.min; - if (typeof min === 'string') { - min = parseFloat(min); - } - return min; + let min = (component as NumberComponent).validate?.min; + if (typeof min === 'string') { + min = parseFloat(min); + } + return min; }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isValidatableNumberComponent(component)) { - return false; - } - if (Number.isNaN(parseFloat(value))) { - return false; - } - if (Number.isNaN(getValidationSetting(component))) { - return false; - } - return true; + const { component, value } = context; + if (!isValidatableNumberComponent(component)) { + return false; + } + if (Number.isNaN(parseFloat(value))) { + return false; + } + if (Number.isNaN(getValidationSetting(component))) { + return false; + } + return true; }; export const validateMinimumValue: RuleFn = async (context: ValidationContext) => { - return validateMinimumValueSync(context); + return validateMinimumValueSync(context); }; export const validateMinimumValueSync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - const min = getValidationSetting(component); - if (min === undefined) { - return null; - } - const parsedValue = typeof value === 'string' ? parseFloat(value) : Number(value); - if (Number.isNaN(parsedValue)) { - throw new ProcessorError( - `Cannot validate value ${parsedValue} because it is invalid`, - context, - 'validate:validateMinimumValue' - ); - } + const { component, value } = context; + if (!shouldValidate(context)) { + return null; + } + const min = getValidationSetting(component); + if (min === undefined) { + return null; + } + const parsedValue = typeof value === 'string' ? parseFloat(value) : Number(value); + if (Number.isNaN(parsedValue)) { + throw new ProcessorError( + `Cannot validate value ${parsedValue} because it is invalid`, + context, + 'validate:validateMinimumValue', + ); + } - return parsedValue >= min - ? null - : new FieldError('min', { ...context, min: String(min), setting: String(min) }); + return parsedValue >= min + ? null + : new FieldError('min', { ...context, min: String(min), setting: String(min) }); }; export const validateMinimumValueInfo: ProcessorInfo = { - name: 'validateMinimumValue', - process: validateMinimumValue, - processSync: validateMinimumValueSync, - shouldProcess: shouldValidate, + name: 'validateMinimumValue', + process: validateMinimumValue, + processSync: validateMinimumValueSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateMinimumWords.ts b/src/process/validation/rules/validateMinimumWords.ts index 21058b46..2dc4b10a 100644 --- a/src/process/validation/rules/validateMinimumWords.ts +++ b/src/process/validation/rules/validateMinimumWords.ts @@ -3,53 +3,57 @@ import { RuleFn, RuleFnSync, TextFieldComponent, ValidationContext } from 'types import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableTextFieldComponent = (component: any): component is TextFieldComponent => { - return component && component.validate?.hasOwnProperty('minWords'); + return component && component.validate?.hasOwnProperty('minWords'); }; const getValidationSetting = (component: TextFieldComponent) => { - let minWords = (component as TextFieldComponent).validate?.minWords; - if (typeof minWords === 'string') { - minWords = parseInt(minWords, 10); - } - return minWords; + let minWords = (component as TextFieldComponent).validate?.minWords; + if (typeof minWords === 'string') { + minWords = parseInt(minWords, 10); + } + return minWords; }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isValidatableTextFieldComponent(component)) { - return false; - } - if (!getValidationSetting(component)) { - return false; - } - if (!value || typeof value !== 'string') { - return false; - } - return true; + const { component, value } = context; + if (!isValidatableTextFieldComponent(component)) { + return false; + } + if (!getValidationSetting(component)) { + return false; + } + if (!value || typeof value !== 'string') { + return false; + } + return true; }; export const validateMinimumWords: RuleFn = async (context: ValidationContext) => { - return validateMinimumWordsSync(context); + return validateMinimumWordsSync(context); }; export const validateMinimumWordsSync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - const minWords = getValidationSetting(component as TextFieldComponent); - if (minWords && value && typeof value === 'string') { - if (value.trim().split(/\s+/).length < minWords) { - const error = new FieldError('minWords', { ...context, length: String(minWords), setting: String(minWords) }); - return error; - } - } + const { component, value } = context; + if (!shouldValidate(context)) { return null; + } + const minWords = getValidationSetting(component as TextFieldComponent); + if (minWords && value && typeof value === 'string') { + if (value.trim().split(/\s+/).length < minWords) { + const error = new FieldError('minWords', { + ...context, + length: String(minWords), + setting: String(minWords), + }); + return error; + } + } + return null; }; export const validateMinimumWordsInfo: ProcessorInfo = { - name: 'validateMinimumWords', - process: validateMinimumWords, - processSync: validateMinimumWordsSync, - shouldProcess: shouldValidate, + name: 'validateMinimumWords', + process: validateMinimumWords, + processSync: validateMinimumWordsSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateMinimumYear.ts b/src/process/validation/rules/validateMinimumYear.ts index 6570171c..21cdb370 100644 --- a/src/process/validation/rules/validateMinimumYear.ts +++ b/src/process/validation/rules/validateMinimumYear.ts @@ -3,64 +3,68 @@ import { DayComponent, RuleFn, RuleFnSync, ValidationContext } from 'types'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableDayComponent = (component: any): component is DayComponent => { - return ( - component && - component?.type === 'day' && - (component.hasOwnProperty('minYear') || component.year?.hasOwnProperty('minYear')) - ); + return ( + component && + component?.type === 'day' && + (component.hasOwnProperty('minYear') || component.year?.hasOwnProperty('minYear')) + ); }; export const shouldValidate = (context: ValidationContext) => { - const { component } = context; - if (!isValidatableDayComponent(component)) { - return false; - } - if (!component.minYear && !component.fields?.year?.minYear) { - return false; - } - return true; + const { component } = context; + if (!isValidatableDayComponent(component)) { + return false; + } + if (!component.minYear && !component.fields?.year?.minYear) { + return false; + } + return true; }; export const validateMinimumYear: RuleFn = async (context: ValidationContext) => { - return validateMinimumYearSync(context); + return validateMinimumYearSync(context); }; export const validateMinimumYearSync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - if (typeof value !== 'string' && typeof value !== 'number') { - throw new ProcessorError(`Cannot validate minimum year for value ${value}`, context, 'validate:validateMinimumYear'); - } - const testValue = typeof value === 'string' ? value : String(value); - const testArr = /\d{4}$/.exec(testValue); - const year = testArr ? testArr[0] : null; - if ( - (component as DayComponent).minYear && - (component as DayComponent).fields?.year?.minYear && - (component as DayComponent).minYear !== (component as DayComponent).fields.year.minYear - ) { - throw new ProcessorError( - 'Cannot validate minimum year, component.minYear and component.fields.year.minYear are not equal', - context, - 'validate:validateMinimumYear' - ); - } - const minYear = (component as DayComponent).minYear; + const { component, value } = context; + if (!shouldValidate(context)) { + return null; + } + if (typeof value !== 'string' && typeof value !== 'number') { + throw new ProcessorError( + `Cannot validate minimum year for value ${value}`, + context, + 'validate:validateMinimumYear', + ); + } + const testValue = typeof value === 'string' ? value : String(value); + const testArr = /\d{4}$/.exec(testValue); + const year = testArr ? testArr[0] : null; + if ( + (component as DayComponent).minYear && + (component as DayComponent).fields?.year?.minYear && + (component as DayComponent).minYear !== (component as DayComponent).fields.year.minYear + ) { + throw new ProcessorError( + 'Cannot validate minimum year, component.minYear and component.fields.year.minYear are not equal', + context, + 'validate:validateMinimumYear', + ); + } + const minYear = (component as DayComponent).minYear; - if (!minYear || !year) { - return null; - } + if (!minYear || !year) { + return null; + } - return +year >= +minYear - ? null - : new FieldError('minYear', { ...context, minYear: String(minYear), setting: String(minYear) }); + return +year >= +minYear + ? null + : new FieldError('minYear', { ...context, minYear: String(minYear), setting: String(minYear) }); }; export const validateMinimumYearInfo: ProcessorInfo = { - name: 'validateMinimumYear', - process: validateMinimumYear, - processSync: validateMinimumYearSync, - shouldProcess: shouldValidate, + name: 'validateMinimumYear', + process: validateMinimumYear, + processSync: validateMinimumYearSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateMultiple.ts b/src/process/validation/rules/validateMultiple.ts index 5f0a6f15..93498727 100644 --- a/src/process/validation/rules/validateMultiple.ts +++ b/src/process/validation/rules/validateMultiple.ts @@ -40,7 +40,7 @@ export const isEligible = (component: Component) => { const isTagsComponent = (component: any): component is TagsComponent => { return component?.type === 'tags'; -} +}; export const emptyValueIsArray = (component: Component) => { // TODO: How do we infer the data model of the compoennt given only its JSON? For now, we have to hardcode component types @@ -75,9 +75,7 @@ export const validateMultiple: RuleFn = async (context: ValidationContext) => { return validateMultipleSync(context); }; -export const validateMultipleSync: RuleFnSync = ( - context: ValidationContext -) => { +export const validateMultipleSync: RuleFnSync = (context: ValidationContext) => { const { component, value } = context; // Skip multiple validation if the component tells us to if (!isEligible(component)) { @@ -87,7 +85,9 @@ export const validateMultipleSync: RuleFnSync = ( const shouldBeMultipleArray = !!component.multiple; const isRequired = !!component.validate?.required; const compModelType = getModelType(component); - const underlyingValueShouldBeArray = ['nestedArray', 'nestedDataArray'].indexOf(compModelType) !== -1 || (isTagsComponent(component) && component.storeas === 'array'); + const underlyingValueShouldBeArray = + ['nestedArray', 'nestedDataArray'].indexOf(compModelType) !== -1 || + (isTagsComponent(component) && component.storeas === 'array'); const valueIsArray = Array.isArray(value); if (shouldBeMultipleArray) { @@ -106,7 +106,9 @@ export const validateMultipleSync: RuleFnSync = ( return isRequired ? new FieldError('array_nonempty', { ...context, setting: true }) : null; } - return Array.isArray(value[0]) && compModelType !== 'any' ? new FieldError('nonarray', { ...context, setting: true }) : null; + return Array.isArray(value[0]) && compModelType !== 'any' + ? new FieldError('nonarray', { ...context, setting: true }) + : null; } else { const error = new FieldError('array', { ...context, setting: true }); // Null/undefined is ok if this value isn't required; anything else should fail @@ -121,10 +123,7 @@ export const validateMultipleSync: RuleFnSync = ( } }; -export const validateMultipleInfo: ProcessorInfo< - ValidationContext, - FieldError | null -> = { +export const validateMultipleInfo: ProcessorInfo = { name: 'validateMultiple', process: validateMultiple, fullValue: true, diff --git a/src/process/validation/rules/validateNumber.ts b/src/process/validation/rules/validateNumber.ts index cacac2f7..63622840 100644 --- a/src/process/validation/rules/validateNumber.ts +++ b/src/process/validation/rules/validateNumber.ts @@ -3,40 +3,40 @@ import { NumberComponent, RuleFn, RuleFnSync, ValidationContext } from '../../.. import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableNumberComponent = (component: any): component is NumberComponent => { - return component && component.type === 'number'; + return component && component.type === 'number'; }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!value) { - return false; - } - if (component.multiple && Array.isArray(value) && value.length === 0) { - return false; - } - if (!isValidatableNumberComponent(component)) { - return false; - } - return true; + const { component, value } = context; + if (!value) { + return false; + } + if (component.multiple && Array.isArray(value) && value.length === 0) { + return false; + } + if (!isValidatableNumberComponent(component)) { + return false; + } + return true; }; export const validateNumber: RuleFn = async (context: ValidationContext) => { - return validateNumberSync(context); + return validateNumberSync(context); }; export const validateNumberSync: RuleFnSync = (context: ValidationContext) => { - const error = new FieldError('number', context); - const { value } = context; - - if (value && typeof value !== 'number') { - return error; - } - return null; + const error = new FieldError('number', context); + const { value } = context; + + if (value && typeof value !== 'number') { + return error; + } + return null; }; export const validateNumberInfo: ProcessorInfo = { - name: 'validateNumber', - process: validateNumber, - processSync: validateNumberSync, - shouldProcess: shouldValidate, -}; \ No newline at end of file + name: 'validateNumber', + process: validateNumber, + processSync: validateNumberSync, + shouldProcess: shouldValidate, +}; diff --git a/src/process/validation/rules/validateRegexPattern.ts b/src/process/validation/rules/validateRegexPattern.ts index 0ab6084f..3bbccdf5 100644 --- a/src/process/validation/rules/validateRegexPattern.ts +++ b/src/process/validation/rules/validateRegexPattern.ts @@ -1,46 +1,56 @@ import { FieldError } from 'error'; -import { TextAreaComponent, TextFieldComponent, RuleFn, RuleFnSync, ValidationContext } from 'types'; +import { + TextAreaComponent, + TextFieldComponent, + RuleFn, + RuleFnSync, + ValidationContext, +} from 'types'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableTextFieldComponent = ( - component: any + component: any, ): component is TextFieldComponent | TextAreaComponent => { - return component && component.validate?.hasOwnProperty('pattern'); + return component && component.validate?.hasOwnProperty('pattern'); }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isValidatableTextFieldComponent(component) || !value) { - return false; - } + const { component, value } = context; + if (!isValidatableTextFieldComponent(component) || !value) { + return false; + } - const pattern = component.validate?.pattern; - if (!pattern || !value || typeof value !== 'string') { - return false; - } - return true; + const pattern = component.validate?.pattern; + if (!pattern || !value || typeof value !== 'string') { + return false; + } + return true; }; export const validateRegexPattern: RuleFn = async (context: ValidationContext) => { - return validateRegexPatternSync(context); + return validateRegexPatternSync(context); }; export const validateRegexPatternSync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context) || !isValidatableTextFieldComponent(component)) { - return null; - } + const { component, value } = context; + if (!shouldValidate(context) || !isValidatableTextFieldComponent(component)) { + return null; + } - const pattern = (component as TextAreaComponent).validate?.pattern; - const regex = new RegExp(`^${pattern}$`); - return typeof value === 'string' && regex.test(value) - ? null - : new FieldError(component.validate?.patternMessage || 'pattern', { ...context, regex: pattern, pattern: pattern, setting: pattern }, 'pattern'); + const pattern = (component as TextAreaComponent).validate?.pattern; + const regex = new RegExp(`^${pattern}$`); + return typeof value === 'string' && regex.test(value) + ? null + : new FieldError( + component.validate?.patternMessage || 'pattern', + { ...context, regex: pattern, pattern: pattern, setting: pattern }, + 'pattern', + ); }; export const validateRegexPatternInfo: ProcessorInfo = { - name: 'validateRegexPattern', - process: validateRegexPattern, - processSync: validateRegexPatternSync, - shouldProcess: shouldValidate, + name: 'validateRegexPattern', + process: validateRegexPattern, + processSync: validateRegexPatternSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateRequired.ts b/src/process/validation/rules/validateRequired.ts index d467ef02..746ab7e2 100644 --- a/src/process/validation/rules/validateRequired.ts +++ b/src/process/validation/rules/validateRequired.ts @@ -1,92 +1,114 @@ import { FieldError } from 'error'; import { - AddressComponentDataObject, - RuleFn, - RuleFnSync, - ValidationContext, - AddressComponent, - DayComponent + AddressComponentDataObject, + RuleFn, + RuleFnSync, + ValidationContext, + AddressComponent, + DayComponent, } from 'types'; import { isEmptyObject, doesArrayDataHaveValue } from '../util'; import { isComponentNestedDataType } from 'utils/formUtil'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isAddressComponent = (component: any): component is AddressComponent => { - return component.type === 'address'; -} + return component.type === 'address'; +}; const isDayComponent = (component: any): component is DayComponent => { - return component.type === 'day'; -} + return component.type === 'day'; +}; const isAddressComponentDataObject = (value: any): value is AddressComponentDataObject => { - return value !== null && typeof value === 'object' && value.mode && value.address && typeof value.address === 'object'; -} + return ( + value !== null && + typeof value === 'object' && + value.mode && + value.address && + typeof value.address === 'object' + ); +}; // Checkboxes and selectboxes consider false to be falsy, whereas other components with // settable values (e.g. radio, select, datamap, container, etc.) consider it truthy const isComponentThatCannotHaveFalseValue = (component: any): boolean => { - return component.type === 'checkbox' || component.type === 'selectboxes' -} + return component.type === 'checkbox' || component.type === 'selectboxes'; +}; -const valueIsPresent = (value: any, considerFalseTruthy: boolean, isNestedDatatype?: boolean): boolean => { - // Evaluate for 3 out of 6 falsy values ("", null, undefined), don't check for 0 - // and only check for false under certain conditions - if (value === null || value === undefined || value === "" || (!considerFalseTruthy && value === false)) { - return false; - } - // Evaluate for empty object - else if (isEmptyObject(value)) { - return false; - } - // Evaluate for empty array - else if (Array.isArray(value) && value.length === 0) { - return false; - } - // Recursively evaluate - else if (typeof value === 'object' && !isNestedDatatype) { - return Object.values(value).some((val) => valueIsPresent(val, considerFalseTruthy, isNestedDatatype)); - } - // If value is an array, check it's children have value - else if (Array.isArray(value) && value.length) { - return doesArrayDataHaveValue(value); - } - return true; -} +const valueIsPresent = ( + value: any, + considerFalseTruthy: boolean, + isNestedDatatype?: boolean, +): boolean => { + // Evaluate for 3 out of 6 falsy values ("", null, undefined), don't check for 0 + // and only check for false under certain conditions + if ( + value === null || + value === undefined || + value === '' || + (!considerFalseTruthy && value === false) + ) { + return false; + } + // Evaluate for empty object + else if (isEmptyObject(value)) { + return false; + } + // Evaluate for empty array + else if (Array.isArray(value) && value.length === 0) { + return false; + } + // Recursively evaluate + else if (typeof value === 'object' && !isNestedDatatype) { + return Object.values(value).some((val) => + valueIsPresent(val, considerFalseTruthy, isNestedDatatype), + ); + } + // If value is an array, check it's children have value + else if (Array.isArray(value) && value.length) { + return doesArrayDataHaveValue(value); + } + return true; +}; export const shouldValidate = (context: ValidationContext) => { - const { component } = context; - if (component.validate?.required && !(component.hidden || component.ephemeralState?.conditionallyHidden)) { - return true; - } - return false; + const { component } = context; + if ( + component.validate?.required && + !(component.hidden || component.ephemeralState?.conditionallyHidden) + ) { + return true; + } + return false; }; export const validateRequired: RuleFn = async (context: ValidationContext) => { - return validateRequiredSync(context); + return validateRequiredSync(context); }; export const validateRequiredSync: RuleFnSync = (context: ValidationContext) => { - const error = new FieldError('required', {...context, setting: true}); - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - if (isAddressComponent(component) && isAddressComponentDataObject(value)) { - return isEmptyObject(value.address) ? error : Object.values(value.address).every((val) => !!val) ? null : error; - } - else if (isDayComponent(component) && value === '00/00/0000') { - return error; - } - else if (isComponentThatCannotHaveFalseValue(component)) { - return !valueIsPresent(value, false, isComponentNestedDataType(component)) ? error : null; - } - return !valueIsPresent(value, true, isComponentNestedDataType(component)) ? error : null; + const error = new FieldError('required', { ...context, setting: true }); + const { component, value } = context; + if (!shouldValidate(context)) { + return null; + } + if (isAddressComponent(component) && isAddressComponentDataObject(value)) { + return isEmptyObject(value.address) + ? error + : Object.values(value.address).every((val) => !!val) + ? null + : error; + } else if (isDayComponent(component) && value === '00/00/0000') { + return error; + } else if (isComponentThatCannotHaveFalseValue(component)) { + return !valueIsPresent(value, false, isComponentNestedDataType(component)) ? error : null; + } + return !valueIsPresent(value, true, isComponentNestedDataType(component)) ? error : null; }; -export const validateRequiredInfo: ProcessorInfo = { - name: 'validateRequired', - process: validateRequired, - processSync: validateRequiredSync, - shouldProcess: shouldValidate, +export const validateRequiredInfo: ProcessorInfo = { + name: 'validateRequired', + process: validateRequired, + processSync: validateRequiredSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateRequiredDay.ts b/src/process/validation/rules/validateRequiredDay.ts index f2917e9a..f56aa847 100644 --- a/src/process/validation/rules/validateRequiredDay.ts +++ b/src/process/validation/rules/validateRequiredDay.ts @@ -3,61 +3,63 @@ import { DayComponent, RuleFn, RuleFnSync, ValidationContext } from 'types'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableDayComponent = (component: any): component is DayComponent => { - return ( - component && - component.type === 'day' && - (component.fields?.day?.required || component.fields?.month?.required || component.fields?.year?.required) - ); + return ( + component && + component.type === 'day' && + (component.fields?.day?.required || + component.fields?.month?.required || + component.fields?.year?.required) + ); }; export const shouldValidate = (context: ValidationContext) => { - const { component } = context; - return isValidatableDayComponent(component); + const { component } = context; + return isValidatableDayComponent(component); }; export const validateRequiredDay: RuleFn = async (context: ValidationContext) => { - return validateRequiredDaySync(context); + return validateRequiredDaySync(context); }; export const validateRequiredDaySync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - if(!isValidatableDayComponent(component)){ - return null; - } - if (!value) { - return new FieldError('requiredDayEmpty', context, 'day'); - } - if (typeof value !== 'string') { - throw new ProcessorError( - `Cannot validate required day field of ${value} because it is not a string`, - context, - 'validate:validateRequiredDay' - ); - } - const [DAY, MONTH, YEAR] = (component).dayFirst ? [0, 1, 2] : [1, 0, 2]; - const values = value.split('/').map((x) => parseInt(x, 10)), - day = values[DAY], - month = values[MONTH], - year = values[YEAR]; - - if (!day && component.fields?.day?.required) { - return new FieldError('requiredDayField', context, 'day'); - } - if (!month && component.fields?.month?.required) { - return new FieldError('requiredMonthField', context, 'day'); - } - if (!year && component.fields?.year?.required) { - return new FieldError('requiredYearField', context, 'day'); - } + const { component, value } = context; + if (!shouldValidate(context)) { + return null; + } + if (!isValidatableDayComponent(component)) { return null; + } + if (!value) { + return new FieldError('requiredDayEmpty', context, 'day'); + } + if (typeof value !== 'string') { + throw new ProcessorError( + `Cannot validate required day field of ${value} because it is not a string`, + context, + 'validate:validateRequiredDay', + ); + } + const [DAY, MONTH, YEAR] = component.dayFirst ? [0, 1, 2] : [1, 0, 2]; + const values = value.split('/').map((x) => parseInt(x, 10)), + day = values[DAY], + month = values[MONTH], + year = values[YEAR]; + + if (!day && component.fields?.day?.required) { + return new FieldError('requiredDayField', context, 'day'); + } + if (!month && component.fields?.month?.required) { + return new FieldError('requiredMonthField', context, 'day'); + } + if (!year && component.fields?.year?.required) { + return new FieldError('requiredYearField', context, 'day'); + } + return null; }; -export const validateRequiredDayInfo: ProcessorInfo = { - name: 'validateRequiredDay', - process: validateRequiredDay, - processSync: validateRequiredDaySync, - shouldProcess: shouldValidate, +export const validateRequiredDayInfo: ProcessorInfo = { + name: 'validateRequiredDay', + process: validateRequiredDay, + processSync: validateRequiredDaySync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateRequiredSurvey.ts b/src/process/validation/rules/validateRequiredSurvey.ts index 5af92342..66fb65b4 100644 --- a/src/process/validation/rules/validateRequiredSurvey.ts +++ b/src/process/validation/rules/validateRequiredSurvey.ts @@ -5,50 +5,54 @@ import { ProcessorInfo } from 'types/process/ProcessorInfo'; type SurveyDataObject = Record; const isValidatableSurveyDataObject = (obj: any): obj is SurveyDataObject => { - return Object.entries(obj).every( - ([key, value]) => typeof key === 'string' && typeof value === 'string' - ); + return Object.entries(obj).every( + ([key, value]) => typeof key === 'string' && typeof value === 'string', + ); }; const isValidatableSurveyComponent = (component: any): component is SurveyComponent => { - return component && component.type === 'survey' && component.validate?.required; + return component && component.type === 'survey' && component.validate?.required; }; export const validateRequiredSurvey: RuleFn = async (context) => { - return validateRequiredSurveySync(context); + return validateRequiredSurveySync(context); }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isValidatableSurveyComponent(component)) { - return false; - } - if (!value) { - return false; - } - return true; + const { component, value } = context; + if (!isValidatableSurveyComponent(component)) { + return false; + } + if (!value) { + return false; + } + return true; }; export const validateRequiredSurveySync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - if (!isValidatableSurveyDataObject(value)) { - throw new ProcessorError(`Cannot validate survey component because ${value} is not valid`, context, 'validate:validateRequiredSurvey'); - } - for (const question of (component as SurveyComponent).questions) { - if (!value[question.value]) { - const error = new FieldError('requiredSurvey', context, 'required'); - return error; - } - } + const { component, value } = context; + if (!shouldValidate(context)) { return null; + } + if (!isValidatableSurveyDataObject(value)) { + throw new ProcessorError( + `Cannot validate survey component because ${value} is not valid`, + context, + 'validate:validateRequiredSurvey', + ); + } + for (const question of (component as SurveyComponent).questions) { + if (!value[question.value]) { + const error = new FieldError('requiredSurvey', context, 'required'); + return error; + } + } + return null; }; -export const validateRequiredSurveyInfo: ProcessorInfo = { - name: 'validateRequiredSurvey', - process: validateRequiredSurvey, - processSync: validateRequiredSurveySync, - shouldProcess: shouldValidate, +export const validateRequiredSurveyInfo: ProcessorInfo = { + name: 'validateRequiredSurvey', + process: validateRequiredSurvey, + processSync: validateRequiredSurveySync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateResourceSelectValue.ts b/src/process/validation/rules/validateResourceSelectValue.ts index 335f66c3..cb4f98d6 100644 --- a/src/process/validation/rules/validateResourceSelectValue.ts +++ b/src/process/validation/rules/validateResourceSelectValue.ts @@ -1,89 +1,97 @@ import { FieldError, ProcessorError } from 'error'; import { SelectComponent, RuleFn, ValidationContext } from 'types'; -import { Evaluator } from 'utils'; import { isEmptyObject, toBoolean } from '../util'; -import { getErrorMessage } from 'utils/error'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableSelectComponent = (component: any): component is SelectComponent => { - return ( - component && - component.type === 'select' && - toBoolean(component.dataSrc === 'resource') && - toBoolean(component.validate?.select) - ); + return ( + component && + component.type === 'select' && + toBoolean(component.dataSrc === 'resource') && + toBoolean(component.validate?.select) + ); }; export const generateUrl = (baseUrl: URL, component: SelectComponent, value: any) => { - const url = baseUrl; - const query = url.searchParams; - if (component.searchField) { - let searchValue = value; - if (component.valueProperty) { - searchValue = value[component.valueProperty]; - } else { - searchValue = value; - } - query.set(component.searchField, typeof searchValue === 'string' ? searchValue : JSON.stringify(searchValue)) - } - if (component.selectFields) { - query.set('select', component.selectFields); - } - if (component.sort) { - query.set('sort', component.sort); - } - if (component.filter) { - const filterQueryStrings = new URLSearchParams(component.filter); - filterQueryStrings.forEach((value, key) => query.set(key, value)); + const url = baseUrl; + const query = url.searchParams; + if (component.searchField) { + let searchValue = value; + if (component.valueProperty) { + searchValue = value[component.valueProperty]; + } else { + searchValue = value; } - return url; + query.set( + component.searchField, + typeof searchValue === 'string' ? searchValue : JSON.stringify(searchValue), + ); + } + if (component.selectFields) { + query.set('select', component.selectFields); + } + if (component.sort) { + query.set('sort', component.sort); + } + if (component.filter) { + const filterQueryStrings = new URLSearchParams(component.filter); + filterQueryStrings.forEach((value, key) => query.set(key, value)); + } + return url; }; export const shouldValidate = (context: ValidationContext) => { - const { component, value, data, config } = context; - // Only run this validation if server-side - if (!config?.server) { - return false; - } - if (!isValidatableSelectComponent(component)) { - return false; - } - if ( - !value || - isEmptyObject(value) || - (Array.isArray(value) && (value as Array>).length === 0) - ) { - return false; - } + const { component, value, config } = context; + // Only run this validation if server-side + if (!config?.server) { + return false; + } + if (!isValidatableSelectComponent(component)) { + return false; + } + if ( + !value || + isEmptyObject(value) || + (Array.isArray(value) && (value as Array>).length === 0) + ) { + return false; + } - // If given an invalid configuration, do not validate the remote value - if (component.dataSrc !== 'resource' || !component.data?.resource) { - return false; - } + // If given an invalid configuration, do not validate the remote value + if (component.dataSrc !== 'resource' || !component.data?.resource) { + return false; + } - return true; + return true; }; export const validateResourceSelectValue: RuleFn = async (context: ValidationContext) => { - const { value, config, component } = context; - if (!shouldValidate(context)) { - return null; - } + const { value, config } = context; + if (!shouldValidate(context)) { + return null; + } - if (!config || !config.database) { - throw new ProcessorError("Can't validate for resource value without a database config object", context, 'validate:validateResourceSelectValue'); - } - try { - const resourceSelectValueResult: boolean = await config.database?.validateResourceSelectValue(context, value); - return (resourceSelectValueResult === true) ? null : new FieldError('select', context); - } - catch (err: any) { - throw new ProcessorError(err.message || err, context, 'validate:validateResourceSelectValue'); - } + if (!config || !config.database) { + throw new ProcessorError( + "Can't validate for resource value without a database config object", + context, + 'validate:validateResourceSelectValue', + ); + } + try { + const resourceSelectValueResult: boolean = await config.database?.validateResourceSelectValue( + context, + value, + ); + return resourceSelectValueResult === true ? null : new FieldError('select', context); + } catch (err: any) { + throw new ProcessorError(err.message || err, context, 'validate:validateResourceSelectValue'); + } }; -export const validateResourceSelectValueInfo: ProcessorInfo = { +export const validateResourceSelectValueInfo: ProcessorInfo = + { name: 'validateResourceSelectValue', process: validateResourceSelectValue, shouldProcess: shouldValidate, -} + }; diff --git a/src/process/validation/rules/validateTime.ts b/src/process/validation/rules/validateTime.ts index 653f5cb1..2e7f3ad7 100644 --- a/src/process/validation/rules/validateTime.ts +++ b/src/process/validation/rules/validateTime.ts @@ -1,49 +1,51 @@ - -import { RuleFn, RuleFnSync, TimeComponent, ValidationContext } from "types"; +import { RuleFn, RuleFnSync, TimeComponent, ValidationContext } from 'types'; import { isComponentDataEmpty } from 'utils/formUtil'; import { FieldError, ProcessorError } from 'error'; import { dayjs } from 'utils/date'; -import { ProcessorInfo } from "types/process/ProcessorInfo"; +import { ProcessorInfo } from 'types/process/ProcessorInfo'; import customParsers from 'dayjs/plugin/customParseFormat'; dayjs.extend(customParsers); const isValidatableTimeComponent = (comp: any): comp is TimeComponent => { - return comp && comp.type === 'time'; -} + return comp && comp.type === 'time'; +}; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isValidatableTimeComponent(component)) { - return false; - } - return true; + const { component } = context; + if (!isValidatableTimeComponent(component)) { + return false; + } + return true; }; export const validateTimeSync: RuleFnSync = (context: ValidationContext) => { - const { component, data, path, value, config } = context; - if (!shouldValidate(context)) { - return null; - } - try { - if (!value || isComponentDataEmpty(component, data, path)) return null; - const format = (component as TimeComponent).dataFormat || 'HH:mm:ss'; - const isValid = dayjs(String(value), format, true).isValid(); - return isValid ? null : new FieldError('time', context); - } - catch (err) { - throw new ProcessorError(`Could not validate time component ${component.key} with value ${value}`, context, 'validate:validateTime'); - } -} + const { component, data, path, value } = context; + if (!shouldValidate(context)) { + return null; + } + try { + if (!value || isComponentDataEmpty(component, data, path)) return null; + const format = (component as TimeComponent).dataFormat || 'HH:mm:ss'; + const isValid = dayjs(String(value), format, true).isValid(); + return isValid ? null : new FieldError('time', context); + } catch (ignoreErr) { + throw new ProcessorError( + `Could not validate time component ${component.key} with value ${value}`, + context, + 'validate:validateTime', + ); + } +}; export const validateTime: RuleFn = async (context: ValidationContext) => { - return validateTimeSync(context); -} + return validateTimeSync(context); +}; -export const validateTimeInfo: ProcessorInfo = { - name: 'validateTime', - process: validateTime, - processSync: validateTimeSync, - shouldProcess: shouldValidate, -} +export const validateTimeInfo: ProcessorInfo = { + name: 'validateTime', + process: validateTime, + processSync: validateTimeSync, + shouldProcess: shouldValidate, +}; diff --git a/src/process/validation/rules/validateUnique.ts b/src/process/validation/rules/validateUnique.ts index 7cfe2b4f..80875a8d 100644 --- a/src/process/validation/rules/validateUnique.ts +++ b/src/process/validation/rules/validateUnique.ts @@ -1,48 +1,51 @@ import { FieldError } from '../../../error/FieldError'; import { RuleFn, ValidationContext } from '../../../types/index'; import { isEmptyObject } from '../util'; -import { ProcessorError} from 'error'; +import { ProcessorError } from 'error'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!component.unique) { - return false; - } + const { component, value } = context; + if (!component.unique) { + return false; + } - if (!value || isEmptyObject(value)) { - return false; - } - return true; + if (!value || isEmptyObject(value)) { + return false; + } + return true; }; export const validateUnique: RuleFn = async (context: ValidationContext) => { - const { value, config, component } = context; - if (!shouldValidate(context)) { - return null; - } + const { value, config, component } = context; + if (!shouldValidate(context)) { + return null; + } - if (!config || !config.database) { - throw new ProcessorError("Can't test for unique value without a database config object", context, 'validate:validateUnique'); - } - try { - const isUnique = await config.database?.isUnique(context, value); - if (typeof isUnique === 'string') { - return new FieldError('unique', { - ...context, - component: {...component, conflictId: isUnique}, - }); - } - return (isUnique === true) ? null : new FieldError('unique', context); - } - catch (err: any) { - throw new ProcessorError(err.message || err, context, 'validate:validateUnique'); + if (!config || !config.database) { + throw new ProcessorError( + "Can't test for unique value without a database config object", + context, + 'validate:validateUnique', + ); + } + try { + const isUnique = await config.database?.isUnique(context, value); + if (typeof isUnique === 'string') { + return new FieldError('unique', { + ...context, + component: { ...component, conflictId: isUnique }, + }); } + return isUnique === true ? null : new FieldError('unique', context); + } catch (err: any) { + throw new ProcessorError(err.message || err, context, 'validate:validateUnique'); + } }; -export const validateUniqueInfo: ProcessorInfo = { - name: 'validateUnique', - fullValue: true, - process: validateUnique, - shouldProcess: shouldValidate, +export const validateUniqueInfo: ProcessorInfo = { + name: 'validateUnique', + fullValue: true, + process: validateUnique, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateUrl.ts b/src/process/validation/rules/validateUrl.ts index 7d912e70..1dacc8de 100644 --- a/src/process/validation/rules/validateUrl.ts +++ b/src/process/validation/rules/validateUrl.ts @@ -3,45 +3,47 @@ import { UrlComponent, RuleFn, RuleFnSync, ValidationContext } from 'types'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isUrlComponent = (component: any): component is UrlComponent => { - return component && component.type === 'url'; + return component && component.type === 'url'; }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isUrlComponent(component)) { - return false; - } - if (!value) { - return false; - } - return true; + const { component, value } = context; + if (!isUrlComponent(component)) { + return false; + } + if (!value) { + return false; + } + return true; }; export const validateUrlSync: RuleFnSync = (context: ValidationContext) => { - const { value } = context; - if (!shouldValidate(context)) { - return null; - } - const error = new FieldError('invalid_url', context, 'url'); - if (typeof value !== 'string') { - return error; - } - // From https://stackoverflow.com/questions/8667070/javascript-regular-expression-to-validate-url - const re = /^(?:(?:(?:https?|ftp):)?\/\/)?(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i; - // From http://stackoverflow.com/questions/46155/validate-email-address-in-javascript - const emailRe = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + const { value } = context; + if (!shouldValidate(context)) { + return null; + } + const error = new FieldError('invalid_url', context, 'url'); + if (typeof value !== 'string') { + return error; + } + // From https://stackoverflow.com/questions/8667070/javascript-regular-expression-to-validate-url + const re = + /^(?:(?:(?:https?|ftp):)?\/\/)?(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i; + // From http://stackoverflow.com/questions/46155/validate-email-address-in-javascript + const emailRe = + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - // Allow urls to be valid if the component is pristine and no value is provided. - return (re.test(value) && !emailRe.test(value)) ? null : error; + // Allow urls to be valid if the component is pristine and no value is provided. + return re.test(value) && !emailRe.test(value) ? null : error; }; export const validateUrl: RuleFn = async (context: ValidationContext) => { - return validateUrlSync(context); + return validateUrlSync(context); }; -export const validateUrlInfo: ProcessorInfo = { - name: 'validateUrl', - process: validateUrl, - processSync: validateUrlSync, - shouldProcess: shouldValidate +export const validateUrlInfo: ProcessorInfo = { + name: 'validateUrl', + process: validateUrl, + processSync: validateUrlSync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/rules/validateUrlSelectValue.ts b/src/process/validation/rules/validateUrlSelectValue.ts index 4a5907e6..5b07ead3 100644 --- a/src/process/validation/rules/validateUrlSelectValue.ts +++ b/src/process/validation/rules/validateUrlSelectValue.ts @@ -1,136 +1,139 @@ import { FieldError, ProcessorError } from 'error'; -import { SelectComponent, RuleFn, ValidationContext, RuleFnSync, FetchFn } from 'types'; +import { SelectComponent, RuleFn, ValidationContext, FetchFn } from 'types'; import { Evaluator } from 'utils'; import { isEmptyObject, toBoolean } from '../util'; import { getErrorMessage } from 'utils/error'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableSelectComponent = (component: any): component is SelectComponent => { - return ( - component && - component.type === 'select' && - toBoolean(component.dataSrc === 'url') && - toBoolean(component.validate?.select) - ); + return ( + component && + component.type === 'select' && + toBoolean(component.dataSrc === 'url') && + toBoolean(component.validate?.select) + ); }; export const generateUrl = (baseUrl: URL, component: SelectComponent, value: any) => { - const url = baseUrl; - const query = url.searchParams; - if (component.searchField) { - let searchValue = value; - if (component.valueProperty) { - searchValue = value[component.valueProperty]; - } else { - searchValue = value; - } - query.set(component.searchField, typeof searchValue === 'string' ? searchValue : JSON.stringify(searchValue)) - } - if (component.selectFields) { - query.set('select', component.selectFields); - } - if (component.sort) { - query.set('sort', component.sort); - } - if (component.filter) { - const filterQueryStrings = new URLSearchParams(component.filter); - filterQueryStrings.forEach((value, key) => query.set(key, value)); + const url = baseUrl; + const query = url.searchParams; + if (component.searchField) { + let searchValue = value; + if (component.valueProperty) { + searchValue = value[component.valueProperty]; + } else { + searchValue = value; } - return url; + query.set( + component.searchField, + typeof searchValue === 'string' ? searchValue : JSON.stringify(searchValue), + ); + } + if (component.selectFields) { + query.set('select', component.selectFields); + } + if (component.sort) { + query.set('sort', component.sort); + } + if (component.filter) { + const filterQueryStrings = new URLSearchParams(component.filter); + filterQueryStrings.forEach((value, key) => query.set(key, value)); + } + return url; }; export const shouldValidate = (context: ValidationContext) => { - const { component, value, data, config } = context; - // Only run this validation if server-side - if (!config?.server) { - return false; - } - if (!isValidatableSelectComponent(component)) { - return false; - } - if ( - !value || - isEmptyObject(value) || - (Array.isArray(value) && (value as Array>).length === 0) - ) { - return false; - } + const { component, value, config } = context; + // Only run this validation if server-side + if (!config?.server) { + return false; + } + if (!isValidatableSelectComponent(component)) { + return false; + } + if ( + !value || + isEmptyObject(value) || + (Array.isArray(value) && (value as Array>).length === 0) + ) { + return false; + } - // If given an invalid configuration, do not validate the remote value - if (component.dataSrc !== 'url' || !component.data?.url || !component.searchField) { - return false; - } + // If given an invalid configuration, do not validate the remote value + if (component.dataSrc !== 'url' || !component.data?.url || !component.searchField) { + return false; + } - return true; + return true; }; export const validateUrlSelectValue: RuleFn = async (context: ValidationContext) => { - const { component, value, data, config } = context; - let _fetch: FetchFn | null = null; - try { - _fetch = context.fetch ? context.fetch : fetch; + const { component, value, data, config } = context; + let _fetch: FetchFn | null = null; + try { + _fetch = context.fetch ? context.fetch : fetch; + } catch (ignoreError) { + _fetch = null; + } + try { + if (!_fetch) { + console.log('You must provide a fetch interface to the fetch processor.'); + return null; } - catch (err) { - _fetch = null; + if (!shouldValidate(context)) { + return null; } - try { - if (!_fetch) { - console.log('You must provide a fetch interface to the fetch processor.'); - return null; - } - if (!shouldValidate(context)) { - return null; - } - const baseUrl = new URL( - Evaluator ? Evaluator.interpolate((component as any).data.url, data, {}) : (component as any).data.url - ); - const url = generateUrl(baseUrl, component as SelectComponent, value); - const headers: Record = (component as any).data.headers - ? (component as any).data.headers.reduce( - (acc: any, header: any) => ({ ...acc, [header.key]: header.value }), - {} - ) - : {}; + const baseUrl = new URL( + Evaluator + ? Evaluator.interpolate((component as any).data.url, data, {}) + : (component as any).data.url, + ); + const url = generateUrl(baseUrl, component as SelectComponent, value); + const headers: Record = (component as any).data.headers + ? (component as any).data.headers.reduce( + (acc: any, header: any) => ({ ...acc, [header.key]: header.value }), + {}, + ) + : {}; - // Set form.io authentication - if ((component as SelectComponent).authenticate && config && config.tokens) { - Object.assign(headers, config.tokens); - } + // Set form.io authentication + if ((component as SelectComponent).authenticate && config && config.tokens) { + Object.assign(headers, config.tokens); + } - try { - const response = await _fetch(url.toString(), { method: 'GET', headers }); - // TODO: should we always expect JSON here? - if (response.ok) { - const data = await response.json(); - const error = new FieldError('select', context); - if (Array.isArray(data)) { - return data && data.length ? null : error; - } - return data ? (isEmptyObject(data) ? error : null) : error; - } - const data = await response.text(); - throw new ProcessorError( - `Component with path ${component.key} returned an error while validating remote value: ${data}`, - context, - 'validate:validateRemoteSelectValue' - ); - } catch (err) { - throw new ProcessorError( - `Component with path ${component.key} returned an error while validating remote value: ${err}`, - context, - 'validate:validateRemoteSelectValue' - ); + try { + const response = await _fetch(url.toString(), { method: 'GET', headers }); + // TODO: should we always expect JSON here? + if (response.ok) { + const data = await response.json(); + const error = new FieldError('select', context); + if (Array.isArray(data)) { + return data && data.length ? null : error; } + return data ? (isEmptyObject(data) ? error : null) : error; + } + const data = await response.text(); + throw new ProcessorError( + `Component with path ${component.key} returned an error while validating remote value: ${data}`, + context, + 'validate:validateRemoteSelectValue', + ); + } catch (err) { + throw new ProcessorError( + `Component with path ${component.key} returned an error while validating remote value: ${err}`, + context, + 'validate:validateRemoteSelectValue', + ); } - catch (err) { - console.error(getErrorMessage(err)); - return null; - } + } catch (err) { + console.error(getErrorMessage(err)); + return null; + } }; export const validateUrlSelectValueInfo: ProcessorInfo = { - name: 'validateUrlSelectValue', - process: validateUrlSelectValue, - shouldProcess: shouldValidate, -} + name: 'validateUrlSelectValue', + process: validateUrlSelectValue, + shouldProcess: shouldValidate, +}; diff --git a/src/process/validation/rules/validateValueProperty.ts b/src/process/validation/rules/validateValueProperty.ts index 51eed950..c3dd3b56 100644 --- a/src/process/validation/rules/validateValueProperty.ts +++ b/src/process/validation/rules/validateValueProperty.ts @@ -4,62 +4,67 @@ import { ListComponent, RuleFn, RuleFnSync, ValidationContext } from 'types'; import { ProcessorInfo } from 'types/process/ProcessorInfo'; const isValidatableListComponent = (comp: any): comp is ListComponent => { - return ( - comp && - comp.type && - (comp.type === "radio" || - comp.type === "selectboxes" || - comp.type === "select") - ); + return ( + comp && + comp.type && + (comp.type === 'radio' || comp.type === 'selectboxes' || comp.type === 'select') + ); }; export const shouldValidate = (context: ValidationContext) => { - const { component, value } = context; - if (!isValidatableListComponent(component)) { - return false; - } - if (component.dataSrc !== 'url') { - return false; - } - if (!value || (typeof value === 'object' && isEmpty(value))) { - return false; - } - const valueProperty = component.valueProperty; - if (!valueProperty) { - return false; - } - return true; + const { component, value } = context; + if (!isValidatableListComponent(component)) { + return false; + } + if (component.dataSrc !== 'url') { + return false; + } + if (!value || (typeof value === 'object' && isEmpty(value))) { + return false; + } + const valueProperty = component.valueProperty; + if (!valueProperty) { + return false; + } + return true; }; export const validateValueProperty: RuleFn = async (context: ValidationContext) => { - return validateValuePropertySync(context); + return validateValuePropertySync(context); }; export const validateValuePropertySync: RuleFnSync = (context: ValidationContext) => { - const { component, value } = context; - if (!shouldValidate(context)) { - return null; - } - const error = new FieldError('invalidValueProperty', context); - // TODO: at some point in the radio component's change pipeline, object values are coerced into strings; testing for - // '[object Object]' is an ugly way to determine whether or not the ValueProperty is invalid, but it'll have to do - // for now - if (component.inputType === 'radio' && (isUndefined(value) || isObject(value) || value === '[object Object]')) { - return error; - } - // TODO: a cousin to the above issue, but sometimes ValueProperty will resolve to a boolean value so the keys in - // e.g. SelectBoxes components will strings coerced from booleans; again, not pretty, but good enough for now - else if (component.inputType !== 'radio') { - if (Object.entries(value as any).some(([key, value]) => value && (key === '[object Object]' || key === 'true' || key === 'false'))) { - return error; - } - } + const { component, value } = context; + if (!shouldValidate(context)) { return null; + } + const error = new FieldError('invalidValueProperty', context); + // TODO: at some point in the radio component's change pipeline, object values are coerced into strings; testing for + // '[object Object]' is an ugly way to determine whether or not the ValueProperty is invalid, but it'll have to do + // for now + if ( + component.inputType === 'radio' && + (isUndefined(value) || isObject(value) || value === '[object Object]') + ) { + return error; + } + // TODO: a cousin to the above issue, but sometimes ValueProperty will resolve to a boolean value so the keys in + // e.g. SelectBoxes components will strings coerced from booleans; again, not pretty, but good enough for now + else if (component.inputType !== 'radio') { + if ( + Object.entries(value as any).some( + ([key, value]) => value && (key === '[object Object]' || key === 'true' || key === 'false'), + ) + ) { + return error; + } + } + return null; }; -export const validateValuePropertyInfo: ProcessorInfo = { - name: 'validateValueProperty', - process: validateValueProperty, - processSync: validateValuePropertySync, - shouldProcess: shouldValidate +export const validateValuePropertyInfo: ProcessorInfo = { + name: 'validateValueProperty', + process: validateValueProperty, + processSync: validateValuePropertySync, + shouldProcess: shouldValidate, }; diff --git a/src/process/validation/util.ts b/src/process/validation/util.ts index 9be41fc4..25d6d8f1 100644 --- a/src/process/validation/util.ts +++ b/src/process/validation/util.ts @@ -7,54 +7,55 @@ import _isObject from 'lodash/isObject'; import _isPlainObject from 'lodash/isPlainObject'; export function isComponentPersistent(component: Component) { - return component.persistent ? component.persistent : true; + return component.persistent ? component.persistent : true; } export function isComponentProtected(component: Component) { - return component.protected ? component.protected : false; + return component.protected ? component.protected : false; } -export function isEmptyObject(obj: any): obj is {} { - return !!obj && Object.keys(obj).length === 0 && obj.constructor === Object; +export function isEmptyObject(obj: any) { + return !!obj && Object.keys(obj).length === 0 && obj.constructor === Object; } export function getComponentErrorField(component: Component, context: ValidationContext) { - const toInterpolate = component.errorLabel || component.label || component.placeholder || component.key; - return Evaluator.interpolate(toInterpolate, context); + const toInterpolate = + component.errorLabel || component.label || component.placeholder || component.key; + return Evaluator.interpolate(toInterpolate, context); } export function toBoolean(value: any) { - switch (typeof value) { - case 'string': - if (value === 'true' || value === '1') { - return true; - } else if (value === 'false' || value === '0') { - return false; - } else { - throw `Cannot coerce string ${value} to boolean}`; - } - case 'boolean': - return value; - default: - return !!value; - } + switch (typeof value) { + case 'string': + if (value === 'true' || value === '1') { + return true; + } else if (value === 'false' || value === '0') { + return false; + } else { + throw `Cannot coerce string ${value} to boolean}`; + } + case 'boolean': + return value; + default: + return !!value; + } } export function isPromise(value: any): value is Promise { - return ( - value && - value.then && - typeof value.then === 'function' && - Object.prototype.toString.call(value) === '[object Promise]' - ); + return ( + value && + value.then && + typeof value.then === 'function' && + Object.prototype.toString.call(value) === '[object Promise]' + ); } -export function isObject(obj: any): obj is Object { - return typeof obj != null && (typeof obj === 'object' || typeof obj === 'function'); +export function isObject(obj: any): obj is object { + return obj != null && (typeof obj === 'object' || typeof obj === 'function'); } const getCustomErrorMessage = ({ errorKeyOrMessage, context }: FieldError): string => - context.component?.errors?.[errorKeyOrMessage] || ''; + context.component?.errors?.[errorKeyOrMessage] || ''; /** * Interpolates @formio/core errors so that they are compatible with the renderer @@ -63,46 +64,46 @@ const getCustomErrorMessage = ({ errorKeyOrMessage, context }: FieldError): stri * @returns {[]} */ export const interpolateErrors = (errors: FieldError[], lang: string = 'en') => { - return errors.map((error) => { - const { errorKeyOrMessage, context } = error; - const i18n = VALIDATION_ERRORS[lang] || {}; - const toInterpolate = getCustomErrorMessage(error) || i18n[errorKeyOrMessage] || errorKeyOrMessage; - const paths: any = []; - context.path.split('.').forEach((part) => { - const match = part.match(/\[([0-9]+)\]$/); - if (match) { - paths.push(part.substring(0, match.index)); - paths.push(parseInt(match[1])); - } - else { - paths.push(part); - } - }); - return { - message: unescapeHTML(Evaluator.interpolateString(toInterpolate, context)), - level: error.level, - path: paths, - context: { - validator: error.ruleName, - hasLabel: context.hasLabel, - key: context.component.key, - label: context.component.label || context.component.placeholder || context.component.key, - path: context.path, - value: context.value, - setting: context.setting, - index: context.index || 0 - } - }; - }); - }; + return errors.map((error) => { + const { errorKeyOrMessage, context } = error; + const i18n = VALIDATION_ERRORS[lang] || {}; + const toInterpolate = + getCustomErrorMessage(error) || i18n[errorKeyOrMessage] || errorKeyOrMessage; + const paths: any = []; + context.path.split('.').forEach((part) => { + const match = part.match(/\[([0-9]+)\]$/); + if (match) { + paths.push(part.substring(0, match.index)); + paths.push(parseInt(match[1])); + } else { + paths.push(part); + } + }); + return { + message: unescapeHTML(Evaluator.interpolateString(toInterpolate, context)), + level: error.level, + path: paths, + context: { + validator: error.ruleName, + hasLabel: context.hasLabel, + key: context.component.key, + label: context.component.label || context.component.placeholder || context.component.key, + path: context.path, + value: context.value, + setting: context.setting, + index: context.index || 0, + }, + }; + }); +}; export const hasValue = (value: any) => { - if (_isObject(value)) { - return !_isEmpty(value); - } + if (_isObject(value)) { + return !_isEmpty(value); + } - return (typeof value === 'number' && !Number.isNaN(value)) || !!value; -} + return (typeof value === 'number' && !Number.isNaN(value)) || !!value; +}; export const doesArrayDataHaveValue = (dataValue: any[] = []): boolean => { if (!Array.isArray(dataValue)) { @@ -116,7 +117,7 @@ export const doesArrayDataHaveValue = (dataValue: any[] = []): boolean => { const isArrayDataComponent = dataValue.every(_isPlainObject); if (isArrayDataComponent) { - return dataValue.some(value => Object.values(value).some(hasValue)); + return dataValue.some((value) => Object.values(value).some(hasValue)); } return dataValue.some(hasValue); diff --git a/src/process/validation/validate.ts b/src/process/validation/validate.ts index a8ebc305..aeb123b4 100644 --- a/src/process/validation/validate.ts +++ b/src/process/validation/validate.ts @@ -1,54 +1,79 @@ -import { Component, ComponentInstances, DataObject, ValidationRuleInfo, ValidationFn, ValidationFnSync, ValidationScope, ProcessContext, ValidationContext, ConditionsScope, ValidationProcessorFn, ValidationProcessorFnSync } from "types"; -import { process, processSync } from "../process"; -import { FieldError } from "error"; -import { validateProcessInfo } from "."; -import { rules } from "./rules"; +import { + Component, + ComponentInstances, + DataObject, + ValidationRuleInfo, + ValidationFn, + ValidationFnSync, + ValidationScope, + ProcessContext, +} from 'types'; +import { process, processSync } from '../process'; +import { FieldError } from 'error'; +import { validateProcessInfo } from '.'; +import { rules } from './rules'; export type ProcessValidateContext = ProcessContext & { - rules: ValidationRuleInfo[]; + rules: ValidationRuleInfo[]; }; export async function processValidate(context: ProcessValidateContext): Promise { - return await process(context); + return await process(context); } export function processValidateSync(context: ProcessValidateContext): ValidationScope { - return processSync(context); + return processSync(context); } export const validator = (rules: ValidationRuleInfo[]): ValidationFn => { - return async (components: Component[], data: DataObject, instances?: ComponentInstances): Promise => { - const scope: ValidationScope = await processValidate({ - components, - data, - instances, - scope: {errors: []}, - processors: [validateProcessInfo], - rules, - }); - return scope.errors; - }; + return async ( + components: Component[], + data: DataObject, + instances?: ComponentInstances, + ): Promise => { + const scope: ValidationScope = await processValidate({ + components, + data, + instances, + scope: { errors: [] }, + processors: [validateProcessInfo], + rules, + }); + return scope.errors; + }; }; export const validatorSync = (rules: ValidationRuleInfo[]): ValidationFnSync => { - return (components: Component[], data: DataObject, instances?: ComponentInstances): FieldError[] => { - return processValidateSync({ - components, - data, - instances, - scope: {errors: []}, - processors: [validateProcessInfo], - rules, - }).errors; - }; + return ( + components: Component[], + data: DataObject, + instances?: ComponentInstances, + ): FieldError[] => { + return processValidateSync({ + components, + data, + instances, + scope: { errors: [] }, + processors: [validateProcessInfo], + rules, + }).errors; + }; }; // Perform a validation on a form asynchonously. -export async function validate(components: Component[], data: DataObject, instances?: ComponentInstances): Promise { - return validator(rules)(components, data, instances); +export async function validate( + components: Component[], + data: DataObject, + instances?: ComponentInstances, +): Promise { + return validator(rules)(components, data, instances); } // Perform a validation on a form synchronously. -export function validateSync(components: Component[], data: DataObject, instances?: ComponentInstances): FieldError[] { - return validatorSync(rules)(components, data, instances); +export function validateSync( + components: Component[], + data: DataObject, + instances?: ComponentInstances, +): FieldError[] { + return validatorSync(rules)(components, data, instances); } diff --git a/src/sdk/Formio.ts b/src/sdk/Formio.ts index e7f90e35..669d87d0 100644 --- a/src/sdk/Formio.ts +++ b/src/sdk/Formio.ts @@ -31,7 +31,7 @@ export interface FormioOptions { */ export enum FormioPathType { Subdirectories = 'Subdirectories', - Subdomains = 'Subdomains' + Subdomains = 'Subdomains', } /** @@ -244,13 +244,15 @@ export class Formio { */ public noProject = false; - /* eslint-disable max-statements */ /** * @constructor * @param {string} path - A project, form, and submission API Url. * @param {FormioOptions} options - Available options to configure the Javascript API. */ - constructor(public path?: string, public options: FormioOptions = {}) { + constructor( + public path?: string, + public options: FormioOptions = {}, + ) { // Ensure we have an instance of Formio. if (!(this instanceof Formio)) { return new Formio(path); @@ -261,11 +263,9 @@ export class Formio { } if (options.hasOwnProperty('base') && options.base) { this.base = options.base; - } - else if (Formio.baseUrl) { + } else if (Formio.baseUrl) { this.base = Formio.baseUrl; - } - else if (window && window.location) { + } else if (window && window.location) { const match = window.location.href.match(/http[s]?:\/\/api./); this.base = match ? match[0] : window.location.origin; } @@ -286,7 +286,7 @@ export class Formio { const project = this.projectUrl || Formio.projectUrl; const projectRegEx = /(^|\/)(project)($|\/[^/]+)/; - const isProjectUrl = (path.search(projectRegEx) !== -1); + const isProjectUrl = path.search(projectRegEx) !== -1; // The baseURL is the same as the projectUrl, and does not contain "/project/MONGO_ID" in // its domain. This is almost certainly against the Open Source server. @@ -296,7 +296,7 @@ export class Formio { } // Normalize to an absolute path. - if ((path.indexOf('http') !== 0) && (path.indexOf('//') !== 0)) { + if (path.indexOf('http') !== 0 && path.indexOf('//') !== 0) { path = this.base + path; } @@ -304,13 +304,13 @@ export class Formio { let hostName = ''; let parts: any = []; if (hostparts) { - hostName = hostparts[1] + hostparts[2]; - path = hostparts.length > 3 ? hostparts[3] : ''; - const queryparts = path.split('?'); - if (queryparts.length > 1) { - path = queryparts[0]; - this.query = `?${queryparts[1]}`; - } + hostName = hostparts[1] + hostparts[2]; + path = hostparts.length > 3 ? hostparts[3] : ''; + const queryparts = path.split('?'); + if (queryparts.length > 1) { + path = queryparts[0]; + this.query = `?${queryparts[1]}`; + } } // Register a specific path. @@ -319,8 +319,8 @@ export class Formio { const regex = new RegExp(`/${name}/([^/]+)`); if (path && path.search(regex) !== -1) { parts = path.match(regex); - (this as any)[`${name}Url`] = parts ? (base + parts[0]) : ''; - (this as any)[`${name}Id`] = (parts.length > 1) ? parts[1] : ''; + (this as any)[`${name}Url`] = parts ? base + parts[0] : ''; + (this as any)[`${name}Id`] = parts.length > 1 ? parts[1] : ''; base += parts[0]; } return base; @@ -333,8 +333,7 @@ export class Formio { const item = items[i]; if (Array.isArray(item)) { registerItems(item, base, true); - } - else { + } else { const newBase = registerPath(item, base); base = staticBase ? base : newBase; } @@ -342,14 +341,13 @@ export class Formio { } }; - if (!this.projectUrl || (this.projectUrl === this.base)) { + if (!this.projectUrl || this.projectUrl === this.base) { // If a project uses Subdirectories path type, we need to specify a projectUrl if (!this.projectUrl && !isProjectUrl && Formio.pathType === 'Subdirectories') { const regex = `^${hostName.replace(/\//g, '\\/')}.[^/]+`; const match = project.match(new RegExp(regex)); this.projectUrl = match ? match[0] : hostName; - } - else { + } else { this.projectUrl = hostName; } } @@ -366,16 +364,14 @@ export class Formio { // Get project id as project/:projectId. registerItems(['project'], hostName); path = path.replace(projectRegEx, ''); - } - else if (hostName === this.base) { + } else if (hostName === this.base) { // Get project id as first part of path (subdirectory). if (hostparts && hostparts.length > 3 && path.split('/').length > 1) { const isFile = path.match(/.json/); const pathParts = path.split('/'); if (isFile) { this.projectUrl = hostName; - } - else { + } else { pathParts.shift(); // Throw away the first /. const projectId = pathParts.shift(); if (projectId) { @@ -385,10 +381,14 @@ export class Formio { } } } - } - else { + } else { // Get project id from subdomain. - if (hostparts && hostparts.length > 2 && (hostparts[2].split('.').length > 2 || hostName.includes('localhost')) && !isNotSubdomainType) { + if ( + hostparts && + hostparts.length > 2 && + (hostparts[2].split('.').length > 2 || hostName.includes('localhost')) && + !isNotSubdomainType + ) { this.projectUrl = hostName; this.projectId = hostparts[2].split('.')[0]; } @@ -402,12 +402,11 @@ export class Formio { // Configure Form urls and form ids. if (/(^|\/)(form)($|\/)/.test(path)) { registerItems(['form', ['submission', 'action', 'v']], this.projectUrl); - } - else { + } else { const subRegEx = new RegExp('/(submission|action|v)($|/.*)'); const subs = path.match(subRegEx); - if ((subs && (subs.length > 1))) { - this.pathType = (subs[1] as FormioPathType); + if (subs && subs.length > 1) { + this.pathType = subs[1] as FormioPathType; } path = path.replace(subRegEx, ''); path = path.replace(/\/$/, ''); @@ -419,7 +418,7 @@ export class Formio { if (items.hasOwnProperty(i)) { const item = items[i]; (this as any)[`${item}sUrl`] = `${this.projectUrl + path}/${item}`; - if ((this.pathType === item) && subs && (subs.length > 2) && subs[2]) { + if (this.pathType === item && subs && subs.length > 2 && subs[2]) { (this as any)[`${item}Id`] = subs[2].replace(/^\/+|\/+$/g, ''); (this as any)[`${item}Url`] = this.projectUrl + path + subs[0]; } @@ -432,7 +431,6 @@ export class Formio { Formio.projectUrl = this.projectUrl; } } - /* eslint-enable max-statements */ /** * Deletes a remote resource of any provided type. @@ -481,9 +479,9 @@ export class Formio { save(type: string, data?: any, opts?: any) { const _id = `${type}Id`; const _url = `${type}Url`; - const method = ((this as any)[_id] || data._id) ? 'put' : 'post'; + const method = (this as any)[_id] || data._id ? 'put' : 'post'; let reqUrl = (this as any)[_id] ? (this as any)[_url] : (this as any)[`${type}sUrl`]; - if (!(this as any)[_id] && data._id && (method === 'put') && !reqUrl.includes(data._id)) { + if (!(this as any)[_id] && data._id && method === 'put' && !reqUrl.includes(data._id)) { reqUrl += `/${data._id}`; } Formio.cache = {}; @@ -506,9 +504,8 @@ export class Formio { query = Formio.serialize((query as any).params); } if (query) { - query = this.query ? (`${this.query}&${query}`) : (`?${query}`); - } - else { + query = this.query ? `${this.query}&${query}` : `?${query}`; + } else { query = this.query; } if (!(this as any)[_id]) { @@ -720,31 +717,30 @@ export class Formio { * @return {Promise} */ loadForm(query?: any, opts?: any) { - return this.load('form', query, opts) - .then((currentForm: any) => { - // Check to see if there isn't a number in vId. - if (!currentForm.revisions || isNaN(parseInt(this.vId))) { - return currentForm; - } - // If a submission already exists but form is marked to load current version of form. - if (currentForm.revisions === 'current' && this.submissionId) { - return currentForm; - } - // eslint-disable-next-line eqeqeq - if (currentForm._vid == this.vId || currentForm.revisionId === this.vId) { - return currentForm; - } - // If they specified a revision form, load the revised form components. - if (query && isObject(query)) { - query = Formio.serialize((query as any).params); - } - if (query) { - query = this.query ? (`${this.query}&${query}`) : (`?${query}`); - } - else { - query = this.query; - } - return this.makeRequest('form', this.vUrl + query, 'get', null, opts) + return this.load('form', query, opts).then((currentForm: any) => { + // Check to see if there isn't a number in vId. + if (!currentForm.revisions || isNaN(parseInt(this.vId))) { + return currentForm; + } + // If a submission already exists but form is marked to load current version of form. + if (currentForm.revisions === 'current' && this.submissionId) { + return currentForm; + } + + if (currentForm._vid == this.vId || currentForm.revisionId === this.vId) { + return currentForm; + } + // If they specified a revision form, load the revised form components. + if (query && isObject(query)) { + query = Formio.serialize((query as any).params); + } + if (query) { + query = this.query ? `${this.query}&${query}` : `?${query}`; + } else { + query = this.query; + } + return ( + this.makeRequest('form', this.vUrl + query, 'get', null, opts) .then((revisionForm: any) => { currentForm._vid = revisionForm._vid; currentForm.components = revisionForm.components; @@ -754,8 +750,9 @@ export class Formio { return Object.assign({}, currentForm); }) // If we couldn't load the revision, just return the original form. - .catch(() => Object.assign({}, currentForm)); - }); + .catch(() => Object.assign({}, currentForm)) + ); + }); } /** @@ -853,12 +850,11 @@ export class Formio { * @return {Promise} */ loadSubmission(query?: any, opts?: any) { - return this.load('submission', query, opts) - .then((submission: any) => { - this.vId = submission._frid || submission._fvid; - this.vUrl = `${this.formUrl}/v/${this.vId}`; - return submission; - }); + return this.load('submission', query, opts).then((submission: any) => { + this.vId = submission._frid || submission._fvid; + this.vUrl = `${this.formUrl}/v/${this.vId}`; + return submission; + }); } /** @@ -1086,8 +1082,7 @@ export class Formio { } if (this.isObjectId(this.projectId)) { return Promise.resolve(this.projectId); - } - else { + } else { return this.loadProject().then((project: any) => { return project._id; }); @@ -1112,8 +1107,7 @@ export class Formio { } if (this.isObjectId(this.formId)) { return Promise.resolve(this.formId); - } - else { + } else { return this.loadForm().then((form: any) => { return form._id; }); @@ -1146,9 +1140,9 @@ export class Formio { * @param {string} options.namespace - The localStorage namespace to use when retrieving tokens from storage. * @return {string} */ - oauthLogoutURI(uri: string, options: string | { namespace: string }): string { - return Formio.oauthLogoutURI(uri, Object.assign({ formio: this }, this.options, options)); - } + oauthLogoutURI(uri: string, options: string | { namespace: string }): string { + return Formio.oauthLogoutURI(uri, Object.assign({ formio: this }, this.options, options)); + } /** * Returns the JWT token for this instance. @@ -1190,8 +1184,8 @@ export class Formio { ignoreCache: true, header: new Headers({ 'x-expire': expire, - 'x-allow': allowed - }) + 'x-allow': allowed, + }), }); } @@ -1227,17 +1221,23 @@ export class Formio { let apiUrl = `/project/${form.project}`; apiUrl += `/form/${form._id}`; apiUrl += `/submission/${this.submissionId}`; - const postfix = form.submissionRevisions && form.settings.changeLog? '/download/changelog' : '/download'; + const postfix = + form.submissionRevisions && form.settings.changeLog ? '/download/changelog' : '/download'; apiUrl += postfix; let download = this.base + apiUrl; return new Promise((resolve, reject) => { - this.getTempToken(3600, `GET:${apiUrl}`).then((tempToken: any) => { - download += `?token=${tempToken.key}`; - resolve(download); - }, () => { - resolve(download); - }).catch(reject); + this.getTempToken(3600, `GET:${apiUrl}`) + .then( + (tempToken: any) => { + download += `?token=${tempToken.key}`; + resolve(download); + }, + () => { + resolve(download); + }, + ) + .catch(reject); }); } @@ -1252,10 +1252,12 @@ export class Formio { */ userPermissions(user?: any, form?: any, submission?: any) { return Promise.all([ - (form !== undefined) ? Promise.resolve(form) : this.loadForm(), - (user !== undefined) ? Promise.resolve(user) : this.currentUser(), - (submission !== undefined || !this.submissionId) ? Promise.resolve(submission) : this.loadSubmission(), - this.accessInfo() + form !== undefined ? Promise.resolve(form) : this.loadForm(), + user !== undefined ? Promise.resolve(user) : this.currentUser(), + submission !== undefined || !this.submissionId + ? Promise.resolve(submission) + : this.loadSubmission(), + this.accessInfo(), ]).then((results: any) => { const form = results.shift(); const user = results.shift() || { _id: false, roles: [] }; @@ -1265,7 +1267,7 @@ export class Formio { create: 'create', read: 'read', update: 'edit', - delete: 'delete' + delete: 'delete', }; const perms: any = { user: user, @@ -1274,16 +1276,15 @@ export class Formio { create: false, read: false, edit: false, - delete: false + delete: false, }; for (const roleName in access.roles) { if (access.roles.hasOwnProperty(roleName)) { const role = access.roles[roleName]; - if (role.default && (user._id === false)) { + if (role.default && user._id === false) { // User is anonymous. Add the anonymous role. user.roles.push(role._id); - } - else if (role.admin && user.roles.indexOf(role._id) !== -1) { + } else if (role.admin && user.roles.indexOf(role._id) !== -1) { perms.create = true; perms.read = true; perms.delete = true; @@ -1298,7 +1299,8 @@ export class Formio { const [perm, scope] = permission.type.split('_'); if (['create', 'read', 'update', 'delete'].includes(perm)) { if (intersection(permission.roles, user.roles).length) { - perms[permMap[perm]] = (scope === 'all') || (!submission || (user._id === submission.owner)); + perms[permMap[perm]] = + scope === 'all' || !submission || user._id === submission.owner; } } } @@ -1311,9 +1313,10 @@ export class Formio { const value = get(submission.data, path); // make it work for single-select Group and multi-select Group const groups = Array.isArray(value) ? value : [value]; - groups.forEach(group => { + groups.forEach((group) => { if ( - group && group._id && // group id is present + group && + group._id && // group id is present user.roles.indexOf(group._id) > -1 // user has group id in his roles ) { if (component.defaultPermission === 'read') { @@ -1370,12 +1373,11 @@ export class Formio { } static getUrlParts(url: string, formio: any) { - const base = (formio && formio.base) ? formio.base : Formio.baseUrl; + const base = formio && formio.base ? formio.base : Formio.baseUrl; let regex = '^(http[s]?:\\/\\/)'; if (base && url.indexOf(base) === 0) { regex += `(${base.replace(/^http[s]?:\/\//, '')})`; - } - else { + } else { regex += '([^/]+)'; } regex += '($|\\/.*)'; @@ -1395,7 +1397,14 @@ export class Formio { return str.join('&'); } - static getRequestArgs(formio: any, type: string, url: string, method?: any, data?: any, opts?: any) { + static getRequestArgs( + formio: any, + type: string, + url: string, + method?: any, + data?: any, + opts?: any, + ) { method = (method || 'GET').toUpperCase(); if (!opts || !isObject(opts)) { opts = {}; @@ -1405,7 +1414,7 @@ export class Formio { url, method, data: data || null, - opts + opts, }; if (type) { @@ -1420,14 +1429,20 @@ export class Formio { static makeStaticRequest(url: string, method?: any, data?: any, opts?: any) { const requestArgs = Formio.getRequestArgs(null, '', url, method, data, opts); - const request = Plugins.pluginWait('preRequest', requestArgs) - .then(() => Plugins.pluginGet('staticRequest', requestArgs) - .then((result: any) => { - if (isNil(result)) { - return Formio.request(requestArgs.url, requestArgs.method, requestArgs.data, requestArgs.opts.header, requestArgs.opts); - } - return result; - })); + const request = Plugins.pluginWait('preRequest', requestArgs).then(() => + Plugins.pluginGet('staticRequest', requestArgs).then((result: any) => { + if (isNil(result)) { + return Formio.request( + requestArgs.url, + requestArgs.method, + requestArgs.data, + requestArgs.opts.header, + requestArgs.opts, + ); + } + return result; + }), + ); return Plugins.pluginAlter('wrapStaticRequestPromise', request, requestArgs); } @@ -1449,7 +1464,14 @@ export class Formio { * @param {boolean} options.getHeaders - Set this if you wish to include the response headers with the return of this method. * @return {Promise} */ - static makeRequest(formio: any, type: string, url: string, method?: string, data?: any, opts?: any) { + static makeRequest( + formio: any, + type: string, + url: string, + method?: string, + data?: any, + opts?: any, + ) { if (!formio) { return Formio.makeStaticRequest(url, method, data, opts); } @@ -1463,17 +1485,23 @@ export class Formio { requestArgs.opts.headers = {}; } requestArgs.opts.headers = defaults(requestArgs.opts.headers, { - 'Accept': 'application/json', - 'Content-type': 'application/json' + Accept: 'application/json', + 'Content-type': 'application/json', }); - const request = Plugins.pluginWait('preRequest', requestArgs) - .then(() => Plugins.pluginGet('request', requestArgs) - .then((result: any) => { - if (isNil(result)) { - return Formio.request(requestArgs.url, requestArgs.method, requestArgs.data, requestArgs.opts.header, requestArgs.opts); - } - return result; - })); + const request = Plugins.pluginWait('preRequest', requestArgs).then(() => + Plugins.pluginGet('request', requestArgs).then((result: any) => { + if (isNil(result)) { + return Formio.request( + requestArgs.url, + requestArgs.method, + requestArgs.data, + requestArgs.opts.header, + requestArgs.opts, + ); + } + return result; + }), + ); return Plugins.pluginAlter('wrapRequestPromise', request, requestArgs); } @@ -1527,10 +1555,14 @@ export class Formio { } // Set up and fetch request - const headers = header || new Headers(opts.headers || { - 'Accept': 'application/json', - 'Content-type': 'application/json' - }); + const headers = + header || + new Headers( + opts.headers || { + Accept: 'application/json', + 'Content-type': 'application/json', + }, + ); const token = Formio.getToken(opts); if (token && !opts.noToken) { headers.set('x-jwt-token', token); @@ -1538,14 +1570,14 @@ export class Formio { // The fetch-ponyfill can't handle a proper Headers class anymore. Change it back to an object. const headerObj: any = {}; - headers.forEach(function(value: any, name: string) { + headers.forEach(function (value: any, name: string) { headerObj[name] = value; }); let options: any = { method: method, headers: headerObj, - mode: 'cors' + mode: 'cors', }; if (data) { options.body = JSON.stringify(data); @@ -1554,135 +1586,138 @@ export class Formio { // Allow plugins to alter the options. options = Plugins.pluginAlter('requestOptions', options, url); if (options.namespace || Formio.namespace) { - opts.namespace = options.namespace || Formio.namespace; + opts.namespace = options.namespace || Formio.namespace; } const requestToken = options.headers['x-jwt-token']; - const result = Plugins.pluginAlter('wrapFetchRequestPromise', Formio.fetch(url, options), - { url, method, data, opts }).then((response: any) => { - // Allow plugins to respond. - response = Plugins.pluginAlter('requestResponse', response, Formio, data); - - if (!response.ok) { - if (response.status === 440) { - Formio.setToken(null, opts); - Formio.events.emit('formio.sessionExpired', response.body || response); + const result = Plugins.pluginAlter('wrapFetchRequestPromise', Formio.fetch(url, options), { + url, + method, + data, + opts, + }) + .then((response: any) => { + // Allow plugins to respond. + response = Plugins.pluginAlter('requestResponse', response, Formio, data); + + if (!response.ok) { + if (response.status === 440) { + Formio.setToken(null, opts); + Formio.events.emit('formio.sessionExpired', response.body || response); + } else if (response.status === 401) { + Formio.events.emit('formio.unauthorized', response.body || response); + } else if (response.status === 416) { + Formio.events.emit('formio.rangeIsNotSatisfiable', response.body || response); + } else if (response.status === 504) { + return Promise.reject(new Error('Network request failed')); + } + // Parse and return the error as a rejected promise to reject this promise + return ( + response.headers.get('content-type').includes('application/json') + ? response.json() + : response.text() + ).then((error: any) => { + return Promise.reject(error); + }); } - else if (response.status === 401) { - Formio.events.emit('formio.unauthorized', response.body || response); + + // Handle fetch results + const respToken = response.headers.get('x-jwt-token'); + + // In some strange cases, the fetch library will return an x-jwt-token without sending + // one to the server. This has even been debugged on the server to verify that no token + // was introduced with the request, but the response contains a token. This is an Invalid + // case where we do not send an x-jwt-token and get one in return for any GET request. + let tokenIntroduced = false; + if ( + method === 'GET' && + !requestToken && + respToken && + !opts.external && + !url.includes('token=') && + !url.includes('x-jwt-token=') + ) { + console.warn('Token was introduced in request.'); + tokenIntroduced = true; } - else if (response.status === 416) { - Formio.events.emit('formio.rangeIsNotSatisfiable', response.body || response); + + if ( + response.status >= 200 && + response.status < 300 && + respToken && + respToken !== '' && + !tokenIntroduced + ) { + Formio.setToken(respToken, { + ...opts, + ...{ fromCurrent: opts.fromCurrent || !!requestToken }, + }); } - else if (response.status === 504) { - return Promise.reject(new Error('Network request failed')); + // 204 is no content. Don't try to .json() it. + if (response.status === 204) { + return {}; } - // Parse and return the error as a rejected promise to reject this promise - return (response.headers.get('content-type').includes('application/json') + + const getResult = response.headers.get('content-type').includes('application/json') ? response.json() - : response.text()) - .then((error: any) => { - return Promise.reject(error); - }); - } + : response.text(); + return getResult.then((result: any) => { + // Add some content-range metadata to the result here + let range = response.headers.get('content-range'); + if (range && isObject(result)) { + range = range.split('/'); + if (range[0] !== '*') { + const skipLimit = range[0].split('-'); + (result as any).skip = Number(skipLimit[0]); + (result as any).limit = skipLimit[1] - skipLimit[0] + 1; + } + (result as any).serverCount = range[1] === '*' ? range[1] : Number(range[1]); + } - // Handle fetch results - const respToken = response.headers.get('x-jwt-token'); - - // In some strange cases, the fetch library will return an x-jwt-token without sending - // one to the server. This has even been debugged on the server to verify that no token - // was introduced with the request, but the response contains a token. This is an Invalid - // case where we do not send an x-jwt-token and get one in return for any GET request. - let tokenIntroduced = false; - if ( - (method === 'GET') && - !requestToken && - respToken && - !opts.external && - !url.includes('token=') && - !url.includes('x-jwt-token=') - ) { - console.warn('Token was introduced in request.'); - tokenIntroduced = true; - } + if (!opts.getHeaders) { + return result; + } + + const headers: any = {}; + response.headers.forEach((item: any, key: any) => { + headers[key] = item; + }); - if ( - response.status >= 200 && - response.status < 300 && - respToken && - respToken !== '' && - !tokenIntroduced - ) { - Formio.setToken(respToken, { - ...opts, - ...{ fromCurrent: (opts.fromCurrent || !!requestToken) } + // Return the result with the headers. + return { + result, + headers, + }; }); - } - // 204 is no content. Don't try to .json() it. - if (response.status === 204) { - return {}; - } + }) + .then((result: any) => { + if (opts.getHeaders) { + return result; + } - const getResult = response.headers.get('content-type').includes('application/json') - ? response.json() - : response.text(); - return getResult.then((result: any) => { - // Add some content-range metadata to the result here - let range = response.headers.get('content-range'); - if (range && isObject(result)) { - range = range.split('/'); - if (range[0] !== '*') { - const skipLimit = range[0].split('-'); - (result as any).skip = Number(skipLimit[0]); - (result as any).limit = skipLimit[1] - skipLimit[0] + 1; - } - (result as any).serverCount = range[1] === '*' ? range[1] : Number(range[1]); + // Cache the response. + if (method === 'GET') { + Formio.cache[cacheKey] = result; } - if (!opts.getHeaders) { - return result; + return Formio.cloneResponse(result); + }) + .catch((err: any) => { + if (err === 'Bad Token' && opts.noToken !== false) { + Formio.setToken(null, opts); + Formio.events.emit('formio.badToken', err); + } + if (err.message) { + err = new Error(`Could not connect to API server (${err.message}): ${url}`); + err.networkError = true; } - const headers: any = {}; - response.headers.forEach((item: any, key: any) => { - headers[key] = item; - }); + if (method === 'GET') { + delete Formio.cache[cacheKey]; + } - // Return the result with the headers. - return { - result, - headers, - }; + return Promise.reject(err); }); - }) - .then((result: any) => { - if (opts.getHeaders) { - return result; - } - - // Cache the response. - if (method === 'GET') { - Formio.cache[cacheKey] = result; - } - - return Formio.cloneResponse(result); - }) - .catch((err: any) => { - if (err === 'Bad Token' && opts.noToken !== false) { - Formio.setToken(null, opts); - Formio.events.emit('formio.badToken', err); - } - if (err.message) { - err = new Error(`Could not connect to API server (${err.message}): ${url}`); - err.networkError = true; - } - - if (method === 'GET') { - delete Formio.cache[cacheKey]; - } - - return Promise.reject(err); - }); return result; } @@ -1697,14 +1732,14 @@ export class Formio { Formio.tokens.formioToken = token || ''; } - static useSessionToken(options: string | { namespace: string}) { + static useSessionToken(options: string | { namespace: string }) { if (typeof localStorage === 'undefined') { return; } - let namespace = options + const namespace = options; if (typeof options === 'object') { - options = options.namespace + options = options.namespace; } const tokenName = `${namespace || Formio.namespace || 'formio'}Token`; const token = localStorage.getItem(tokenName); @@ -1736,7 +1771,7 @@ export class Formio { */ static setToken(token: any = '', opts: any = {}) { token = token || ''; - opts = (typeof opts === 'string') ? { namespace: opts } : opts || {}; + opts = typeof opts === 'string' ? { namespace: opts } : opts || {}; const tokenName = `${opts.namespace || Formio.namespace || 'formio'}Token`; if (!Formio.tokens) { @@ -1753,8 +1788,7 @@ export class Formio { // iOS in private browse mode will throw an error but we can't detect ahead of time that we are in private mode. try { storage.removeItem(tokenName); - } - catch (err: any) { + } catch (ignoreErr: any) { cookies.erase(tokenName, { path: '/' }); } Formio.tokens[tokenName] = token; @@ -1766,8 +1800,7 @@ export class Formio { // iOS in private browse mode will throw an error but we can't detect ahead of time that we are in private mode. try { storage.setItem(tokenName, token); - } - catch (err: any) { + } catch (ignoreErr: any) { cookies.set(tokenName, token, { path: '/' }); } } @@ -1784,7 +1817,7 @@ export class Formio { * @return {*} */ static getToken(options?: any) { - options = (typeof options === 'string') ? { namespace: options } : options || {}; + options = typeof options === 'string' ? { namespace: options } : options || {}; const tokenName = `${options.namespace || Formio.namespace || 'formio'}Token`; const decodedTokenName = options.decode ? `${tokenName}Decoded` : tokenName; if (!Formio.tokens) { @@ -1800,12 +1833,13 @@ export class Formio { : localStorage.getItem(tokenName); Formio.tokens[tokenName] = token || ''; if (options.decode) { - Formio.tokens[decodedTokenName] = Formio.tokens[tokenName] ? jwtDecode(Formio.tokens[tokenName]) : {}; + Formio.tokens[decodedTokenName] = Formio.tokens[tokenName] + ? jwtDecode(Formio.tokens[tokenName]) + : {}; return Formio.tokens[decodedTokenName]; } return Formio.tokens[tokenName]; - } - catch (e: any) { + } catch (ignoreError: any) { Formio.tokens[tokenName] = cookies.get(tokenName); return ''; } @@ -1833,16 +1867,14 @@ export class Formio { // iOS in private browse mode will throw an error but we can't detect ahead of time that we are in private mode. try { return storage.removeItem(userName); - } - catch (err: any) { + } catch (ignoreError: any) { return cookies.erase(userName, { path: '/' }); } } // iOS in private browse mode will throw an error but we can't detect ahead of time that we are in private mode. try { storage.setItem(userName, JSON.stringify(user)); - } - catch (err: any) { + } catch (ignoreError: any) { cookies.set(userName, JSON.stringify(user), { path: '/' }); } @@ -1862,13 +1894,11 @@ export class Formio { const userName = `${options.namespace || Formio.namespace || 'formio'}User`; try { return JSON.parse( - (localStorage.getItem('useSessionToken') - ? sessionStorage - : localStorage - ).getItem(userName) || '' + (localStorage.getItem('useSessionToken') ? sessionStorage : localStorage).getItem( + userName, + ) || '', ); - } - catch (e: any) { + } catch (ignoreError: any) { return JSON.parse(cookies.get(userName)!); } } @@ -2029,7 +2059,7 @@ export class Formio { static currentUser(formio?: any, options: any = {}) { let authUrl = Formio.authUrl; if (!authUrl) { - authUrl = formio ? formio.projectUrl : (Formio.projectUrl || Formio.baseUrl); + authUrl = formio ? formio.projectUrl : Formio.projectUrl || Formio.baseUrl; } authUrl += '/current'; if (!options.ignoreCache || options.fromCurrent) { @@ -2038,7 +2068,7 @@ export class Formio { return Plugins.pluginAlter('wrapStaticRequestPromise', Promise.resolve(user), { url: authUrl, method: 'GET', - options + options, }); } } @@ -2048,16 +2078,17 @@ export class Formio { return Plugins.pluginAlter('wrapStaticRequestPromise', Promise.resolve(null), { url: authUrl, method: 'GET', - options + options, }); } options.fromCurrent = true; - return Formio.makeRequest(formio, 'currentUser', authUrl, 'GET', null, options) - .then((response: any) => { + return Formio.makeRequest(formio, 'currentUser', authUrl, 'GET', null, options).then( + (response: any) => { Formio.setUser(response, options); return response; - }); + }, + ); } /** @@ -2070,7 +2101,11 @@ export class Formio { */ static logout(formio?: any, options: any = {}) { options.formio = formio; - const projectUrl = Formio.authUrl ? Formio.authUrl : (formio ? formio.projectUrl : Formio.baseUrl); + const projectUrl = Formio.authUrl + ? Formio.authUrl + : formio + ? formio.projectUrl + : Formio.baseUrl; const logout = () => { Formio.setToken(null, options); Formio.setUser(null, options); @@ -2078,14 +2113,14 @@ export class Formio { localStorage.removeItem('useSessionToken'); }; return Formio.makeRequest(formio, 'logout', `${projectUrl}/logout`) - .then(function(result: any) { + .then(function (result: any) { logout(); if (result.shouldRedirect && result.url) { window.location.href = result.url; } return result; }) - .catch(function(err: any) { + .catch(function (err: any) { logout(); throw err; }); @@ -2116,19 +2151,21 @@ export class Formio { pageQuery.paths = []; const hashes = location.hash.substr(1).replace(/\?/g, '&').split('&'); let parts = []; - location.search.substr(1).split('&').forEach(function(item) { - parts = item.split('='); - if (parts.length > 1) { - pageQuery[parts[0]] = parts[1] && decodeURIComponent(parts[1]); - } - }); + location.search + .substr(1) + .split('&') + .forEach(function (item) { + parts = item.split('='); + if (parts.length > 1) { + pageQuery[parts[0]] = parts[1] && decodeURIComponent(parts[1]); + } + }); - hashes.forEach(function(item) { + hashes.forEach(function (item) { parts = item.split('='); if (parts.length > 1) { pageQuery[parts[0]] = parts[1] && decodeURIComponent(parts[1]); - } - else if (item.indexOf('/') === 0) { + } else if (item.indexOf('/') === 0) { pageQuery.paths = item.substr(1).split('/'); } }); @@ -2147,15 +2184,14 @@ export class Formio { return Formio.currentUser(formio, { external: true, headers: { - Authorization: `Bearer ${token}` - } + Authorization: `Bearer ${token}`, + }, }); } static oauthLogoutURI(uri: string, options: string | { namespace: string }): string { - options = (typeof options === 'string') ? { namespace: options } : options || {}; + options = typeof options === 'string' ? { namespace: options } : options || {}; const logoutURIName = `${options.namespace || Formio.namespace || 'formio'}LogoutAuthUrl`; - Formio.tokens[logoutURIName]; localStorage.setItem(logoutURIName, uri); return Formio.tokens[logoutURIName]; } @@ -2248,12 +2284,13 @@ export class Formio { * @return {Promise} */ static oktaInit(options: any = {}) { - if (typeof OktaAuth !== undefined) { + if (typeof OktaAuth !== 'undefined') { options.OktaAuth = OktaAuth; } - if (typeof options.OktaAuth === undefined) { - const errorMessage = 'Cannot find OktaAuth. Please include the Okta JavaScript SDK within your application. See https://developer.okta.com/code/javascript/okta_auth_sdk for an example.'; + if (typeof options.OktaAuth === 'undefined') { + const errorMessage = + 'Cannot find OktaAuth. Please include the Okta JavaScript SDK within your application. See https://developer.okta.com/code/javascript/okta_auth_sdk for an example.'; console.warn(errorMessage); return Promise.reject(errorMessage); } @@ -2261,13 +2298,14 @@ export class Formio { const Okta = options.OktaAuth; delete options.OktaAuth; const authClient = new Okta(options); - authClient.tokenManager.get('accessToken') + authClient.tokenManager + .get('accessToken') .then((accessToken: any) => { if (accessToken) { resolve(Formio.oAuthCurrentUser(options.formio, accessToken.accessToken)); - } - else if (location.hash) { - authClient.token.parseFromUrl() + } else if (location.hash) { + authClient.token + .parseFromUrl() .then((token: any) => { authClient.tokenManager.add('accessToken', token); resolve(Formio.oAuthCurrentUser(options.formio, token.accessToken)); @@ -2276,11 +2314,10 @@ export class Formio { console.warn(err); reject(err); }); - } - else { + } else { authClient.token.getWithRedirect({ responseType: 'token', - scopes: options.scopes + scopes: options.scopes, }); resolve(false); } @@ -2331,7 +2368,13 @@ export class Formio { * @param {boolean} polling - Determines if polling should be used to determine if they library is ready to use. If set to false, then it will rely on a global callback called ${name}Callback where "name" is the first property passed to this method. When this is called, that will indicate when the library is ready. In most cases, you will want to pass true to this parameter to initiate a polling method to check for the library availability in the global context. * @return {Promise} - A promise that will resolve when the plugin is ready to be used. */ - static requireLibrary(name: string, property: string, src: string | Array, polling: boolean = false, onload?: (ready: Promise) => void) { + static requireLibrary( + name: string, + property: string, + src: string | Array, + polling: boolean = false, + onload?: (ready: Promise) => void, + ) { if (!Formio.libraries.hasOwnProperty(name)) { Formio.libraries[name] = {}; Formio.libraries[name].ready = new Promise((resolve, reject) => { @@ -2349,8 +2392,7 @@ export class Formio { const plugin = get(window, property); if (plugin) { Formio.libraries[name].resolve(plugin); - } - else { + } else { src = Array.isArray(src) ? src : [src]; src.forEach((lib: any) => { let attrs: any = {}; @@ -2434,10 +2476,7 @@ export class Formio { * @return {Promise} - A promise that will resolve when the library is ready to be used. */ static libraryReady(name: string) { - if ( - Formio.libraries.hasOwnProperty(name) && - Formio.libraries[name].ready - ) { + if (Formio.libraries.hasOwnProperty(name) && Formio.libraries[name].ready) { return Formio.libraries[name].ready; } @@ -2484,7 +2523,7 @@ export class Formio { public static getPlugin = Plugins.getPlugin; public static pluginWait = Plugins.pluginWait; public static pluginGet = Plugins.pluginGet; - public static pluginAlter = Plugins.pluginAlter + public static pluginAlter = Plugins.pluginAlter; } // Adds Formio to the Plugins Interface. diff --git a/src/sdk/Plugins.ts b/src/sdk/Plugins.ts index 8f93a76f..52adcadd 100644 --- a/src/sdk/Plugins.ts +++ b/src/sdk/Plugins.ts @@ -4,158 +4,164 @@ import { noop, isNil } from 'lodash'; * The plugin initialization function, which will receive the Formio interface as its first argument. */ export interface PluginInitFunction { - /** - * @param Formio - The Formio interface class. - */ - (Formio: any): void; + /** + * @param Formio - The Formio interface class. + */ + (Formio: any): void; } /** * Function that is called when the plugin is deregistered. */ export interface PluginDeregisterFunction { - /** - * @param Formio The Formio interface class. - */ - (Formio: any): void; + /** + * @param Formio The Formio interface class. + */ + (Formio: any): void; } /** * A Formio Plugin interface. */ export interface Plugin { - /** - * The name of the plugin. - */ - __name: string, - - /** - * The priority of this plugin. - */ - priority: number, - - /** - * An initialization function called when registered with Formio. - */ - init: PluginInitFunction, - - /** - * Called when the plugin is deregistered. - */ - deregister: PluginDeregisterFunction, + /** + * The name of the plugin. + */ + __name: string; + + /** + * The priority of this plugin. + */ + priority: number; + + /** + * An initialization function called when registered with Formio. + */ + init: PluginInitFunction; + + /** + * Called when the plugin is deregistered. + */ + deregister: PluginDeregisterFunction; } /** * The Form.io Plugins allow external systems to "hook" into the default behaviors of the JavaScript SDK. */ export default class Plugins { - /** - * An array of Form.io Plugins. - */ - public static plugins: Array = []; - - /** - * The Formio class. - */ - public static Formio: any; - - /** - * Returns the plugin identity. - * - * @param value - */ - static identity(value: string) { - return value; + /** + * An array of Form.io Plugins. + */ + public static plugins: Array = []; + + /** + * The Formio class. + */ + public static Formio: any; + + /** + * Returns the plugin identity. + * + * @param value + */ + static identity(value: string) { + return value; + } + + /** + * De-registers a plugin. + * @param plugin The plugin you wish to deregister. + */ + static deregisterPlugin(plugin: Plugin | string) { + const beforeLength = Plugins.plugins.length; + Plugins.plugins = Plugins.plugins.filter((p) => { + if (p !== plugin && p.__name !== plugin) { + return true; + } + + (p.deregister || noop).call(plugin, Plugins.Formio); + return false; + }); + return beforeLength !== Plugins.plugins.length; + } + + /** + * Registers a new plugin. + * + * @param plugin The Plugin object. + * @param name The name of the plugin you wish to register. + */ + static registerPlugin(plugin: Plugin, name: string) { + Plugins.plugins.push(plugin); + Plugins.plugins.sort((a, b) => (b.priority || 0) - (a.priority || 0)); + plugin.__name = name; + (plugin.init || noop).call(plugin, Plugins.Formio); + } + + /** + * Returns a plugin provided the name of the plugin. + * @param name The name of the plugin you would like to get. + */ + static getPlugin(name: string) { + for (const plugin of Plugins.plugins) { + if (plugin.__name === name) { + return plugin; + } } - /** - * De-registers a plugin. - * @param plugin The plugin you wish to deregister. - */ - static deregisterPlugin(plugin: (Plugin | string)) { - const beforeLength = Plugins.plugins.length; - Plugins.plugins = Plugins.plugins.filter((p) => { - if (p !== plugin && p.__name !== plugin) { - return true; - } - - (p.deregister || noop).call(plugin, Plugins.Formio); - return false; - }); - return beforeLength !== Plugins.plugins.length; - } - - /** - * Registers a new plugin. - * - * @param plugin The Plugin object. - * @param name The name of the plugin you wish to register. - */ - static registerPlugin(plugin: Plugin, name: string) { - Plugins.plugins.push(plugin); - Plugins.plugins.sort((a, b) => (b.priority || 0) - (a.priority || 0)); - plugin.__name = name; - (plugin.init || noop).call(plugin, Plugins.Formio); - } - - /** - * Returns a plugin provided the name of the plugin. - * @param name The name of the plugin you would like to get. - */ - static getPlugin(name: string) { - for (const plugin of Plugins.plugins) { - if (plugin.__name === name) { - return plugin; - } - } - - return null; - } - - /** - * Wait for a plugin function to complete. - * @param pluginFn - A function within the plugin. - * @param args - */ - static pluginWait(pluginFn: any, ...args: any[]) { - return Promise.all(Plugins.plugins.map((plugin: Plugin) => - ((plugin as any)[pluginFn] || noop).call(plugin, ...args))); - } - - /** - * Gets a value from a Plugin - * @param pluginFn - * @param args - */ - static pluginGet(pluginFn: any, ...args: any[]) { - const callPlugin = (index: any): any => { - const plugin = Plugins.plugins[index]; - - if (!plugin) { - return Promise.resolve(null); - } - - return Promise.resolve(((plugin as any)[pluginFn] || noop).call(plugin, ...args)) - .then((result) => { - if (!isNil(result)) { - return result; - } - - return callPlugin(index + 1); - }); - }; - return callPlugin(0); - } - - /** - * Allows a Plugin to alter the behavior of the JavaScript library. - * - * @param pluginFn - * @param value - * @param args - */ - static pluginAlter(pluginFn: any, value: any, ...args: any[]) { - return Plugins.plugins.reduce((value, plugin) => - ((plugin as any)[pluginFn] || Plugins.identity)(value, ...args), value); - } -} \ No newline at end of file + return null; + } + + /** + * Wait for a plugin function to complete. + * @param pluginFn - A function within the plugin. + * @param args + */ + static pluginWait(pluginFn: any, ...args: any[]) { + return Promise.all( + Plugins.plugins.map((plugin: Plugin) => + ((plugin as any)[pluginFn] || noop).call(plugin, ...args), + ), + ); + } + + /** + * Gets a value from a Plugin + * @param pluginFn + * @param args + */ + static pluginGet(pluginFn: any, ...args: any[]) { + const callPlugin = (index: any): any => { + const plugin = Plugins.plugins[index]; + + if (!plugin) { + return Promise.resolve(null); + } + + return Promise.resolve(((plugin as any)[pluginFn] || noop).call(plugin, ...args)).then( + (result) => { + if (!isNil(result)) { + return result; + } + + return callPlugin(index + 1); + }, + ); + }; + return callPlugin(0); + } + + /** + * Allows a Plugin to alter the behavior of the JavaScript library. + * + * @param pluginFn + * @param value + * @param args + */ + static pluginAlter(pluginFn: any, value: any, ...args: any[]) { + return Plugins.plugins.reduce( + (value, plugin) => ((plugin as any)[pluginFn] || Plugins.identity)(value, ...args), + value, + ); + } +} diff --git a/src/sdk/__tests__/Formio.test.ts b/src/sdk/__tests__/Formio.test.ts index e49612ac..6d7d90ca 100644 --- a/src/sdk/__tests__/Formio.test.ts +++ b/src/sdk/__tests__/Formio.test.ts @@ -1,3 +1,5 @@ +/* eslint-disable mocha/no-setup-in-describe */ +/* eslint-disable mocha/no-nested-tests */ import { Formio } from '../Formio'; import { fastCloneDeep } from '../../utils/fastCloneDeep'; import assert from 'power-assert'; @@ -19,29 +21,33 @@ const formId = '59bbe2ec8c246100079191ab'; const submissionId = '59bbe2ec8c246100079191ac'; const actionId = '59bbe2ec8c246100079191ad'; -const generateID = function() { +const generateID = function () { return chance.string({ length: 24, pool: '0123456789abcdef' }); }; -const runTests = function(fn: any, options?: any) { +const runTests = function (fn: any, options?: any) { const tests = {}; const noBefore = fn(tests); if (!noBefore) { - beforeEach(() => { + beforeEach(function () { Formio.setBaseUrl(baseUrl); Formio.projectUrlSet = false; Formio.projectUrl = 'https://api.form.io'; }); } each(tests, (test: any, path) => { - it(`Should initialize for ${path}`, (done) => { + it(`Should initialize for ${path}`, function (done) { if (typeof test === 'function') { + // eslint-disable-next-line mocha/no-empty-description test(); - } - else { + } else { const formio: any = new Formio(path, options); for (const param in test) { - assert.equal(formio[param], test[param], `${param} is not equal. ${formio[param]} == ${test[param]}\n`); + assert.equal( + formio[param], + test[param], + `${param} is not equal. ${formio[param]} == ${test[param]}\n`, + ); } } done(); @@ -49,128 +55,128 @@ const runTests = function(fn: any, options?: any) { }); }; -describe('Formio.js Tests', () => { - describe('Formio Constructor Tests', () => { +describe('Formio.js Tests', function () { + describe('Formio Constructor Tests', function () { runTests((tests: any) => { - tests[`http://form.io/project/${ projectId }/form/${ formId}`] = { - projectUrl: `http://form.io/project/${ projectId}`, + tests[`http://form.io/project/${projectId}/form/${formId}`] = { + projectUrl: `http://form.io/project/${projectId}`, projectsUrl: 'http://form.io/project', projectId: projectId, - formsUrl: `http://form.io/project/${ projectId }/form`, - formUrl: `http://form.io/project/${ projectId }/form/${ formId}`, + formsUrl: `http://form.io/project/${projectId}/form`, + formUrl: `http://form.io/project/${projectId}/form/${formId}`, formId: formId, - actionsUrl: `http://form.io/project/${ projectId }/form/${ formId }/action`, + actionsUrl: `http://form.io/project/${projectId}/form/${formId}/action`, actionUrl: '', actionId: '', - submissionsUrl: `http://form.io/project/${ projectId }/form/${ formId }/submission`, + submissionsUrl: `http://form.io/project/${projectId}/form/${formId}/submission`, submissionUrl: '', submissionId: '', - query: '' + query: '', }; - tests[`http://form.io/form/${ formId}`] = { + tests[`http://form.io/form/${formId}`] = { projectUrl: 'http://form.io', projectsUrl: `${baseUrl}/project`, projectId: '', formsUrl: 'http://form.io/form', - formUrl: `http://form.io/form/${ formId}`, + formUrl: `http://form.io/form/${formId}`, formId: formId, - actionsUrl: `http://form.io/form/${ formId }/action`, + actionsUrl: `http://form.io/form/${formId}/action`, actionUrl: '', actionId: '', - submissionsUrl: `http://form.io/form/${ formId }/submission`, + submissionsUrl: `http://form.io/form/${formId}/submission`, submissionUrl: '', submissionId: '', - query: '' + query: '', }; - tests[`http://form.io/form/${ formId }/submission/${ submissionId}`] = { + tests[`http://form.io/form/${formId}/submission/${submissionId}`] = { projectUrl: 'http://form.io', projectsUrl: `${baseUrl}/project`, projectId: '', formsUrl: 'http://form.io/form', - formUrl: `http://form.io/form/${ formId}`, + formUrl: `http://form.io/form/${formId}`, formId: formId, - actionsUrl: `http://form.io/form/${ formId }/action`, + actionsUrl: `http://form.io/form/${formId}/action`, actionUrl: '', actionId: '', - submissionsUrl: `http://form.io/form/${ formId }/submission`, - submissionUrl: `http://form.io/form/${ formId }/submission/${ submissionId}`, + submissionsUrl: `http://form.io/form/${formId}/submission`, + submissionUrl: `http://form.io/form/${formId}/submission/${submissionId}`, submissionId: submissionId, - query: '' + query: '', }; - tests[`http://form.io/form/${ formId }/action/${ actionId}`] = { + tests[`http://form.io/form/${formId}/action/${actionId}`] = { projectUrl: 'http://form.io', projectsUrl: `${baseUrl}/project`, projectId: '', formsUrl: 'http://form.io/form', - formUrl: `http://form.io/form/${ formId}`, + formUrl: `http://form.io/form/${formId}`, formId: formId, - actionsUrl: `http://form.io/form/${ formId }/action`, - actionUrl: `http://form.io/form/${ formId }/action/${ actionId}`, + actionsUrl: `http://form.io/form/${formId}/action`, + actionUrl: `http://form.io/form/${formId}/action/${actionId}`, actionId: actionId, - submissionsUrl: `http://form.io/form/${ formId }/submission`, + submissionsUrl: `http://form.io/form/${formId}/submission`, submissionUrl: '', submissionId: '', - query: '' + query: '', }; - tests[`http://form.io/project/${ projectId }/form/${ formId }/action/${ actionId}`] = { - projectUrl: `http://form.io/project/${ projectId}`, + tests[`http://form.io/project/${projectId}/form/${formId}/action/${actionId}`] = { + projectUrl: `http://form.io/project/${projectId}`, projectsUrl: 'http://form.io/project', projectId: projectId, - formsUrl: `http://form.io/project/${ projectId }/form`, - formUrl: `http://form.io/project/${ projectId }/form/${ formId}`, + formsUrl: `http://form.io/project/${projectId}/form`, + formUrl: `http://form.io/project/${projectId}/form/${formId}`, formId: formId, - actionsUrl: `http://form.io/project/${ projectId }/form/${ formId }/action`, - actionUrl: `http://form.io/project/${ projectId }/form/${ formId }/action/${ actionId}`, + actionsUrl: `http://form.io/project/${projectId}/form/${formId}/action`, + actionUrl: `http://form.io/project/${projectId}/form/${formId}/action/${actionId}`, actionId: actionId, - submissionsUrl: `http://form.io/project/${ projectId }/form/${ formId }/submission`, + submissionsUrl: `http://form.io/project/${projectId}/form/${formId}/submission`, submissionUrl: '', submissionId: '', - query: '' + query: '', }; - tests[`http://api.form.io/project/${ projectId}`] = { - projectUrl: `http://api.form.io/project/${ projectId}`, + tests[`http://api.form.io/project/${projectId}`] = { + projectUrl: `http://api.form.io/project/${projectId}`, projectsUrl: 'http://api.form.io/project', projectId: projectId, - formsUrl: `http://api.form.io/project/${ projectId }/form`, + formsUrl: `http://api.form.io/project/${projectId}/form`, formUrl: '', formId: '', - actionsUrl: `http://api.form.io/project/${ projectId }/action`, + actionsUrl: `http://api.form.io/project/${projectId}/action`, actionUrl: '', actionId: '', - submissionsUrl: `http://api.form.io/project/${ projectId }/submission`, + submissionsUrl: `http://api.form.io/project/${projectId}/submission`, submissionUrl: '', submissionId: '', - query: '' + query: '', }; - tests[`http://form.io/project/${ projectId }/form/${ formId }/submission/${ submissionId}`] = { - projectUrl: `http://form.io/project/${ projectId}`, + tests[`http://form.io/project/${projectId}/form/${formId}/submission/${submissionId}`] = { + projectUrl: `http://form.io/project/${projectId}`, projectsUrl: 'http://form.io/project', projectId: projectId, - formsUrl: `http://form.io/project/${ projectId }/form`, - formUrl: `http://form.io/project/${ projectId }/form/${ formId}`, + formsUrl: `http://form.io/project/${projectId}/form`, + formUrl: `http://form.io/project/${projectId}/form/${formId}`, formId: formId, - actionsUrl: `http://form.io/project/${ projectId }/form/${ formId }/action`, + actionsUrl: `http://form.io/project/${projectId}/form/${formId}/action`, actionUrl: '', actionId: '', - submissionsUrl: `http://form.io/project/${ projectId }/form/${ formId }/submission`, - submissionUrl: `http://form.io/project/${ projectId }/form/${ formId }/submission/${ submissionId}`, + submissionsUrl: `http://form.io/project/${projectId}/form/${formId}/submission`, + submissionUrl: `http://form.io/project/${projectId}/form/${formId}/submission/${submissionId}`, submissionId: submissionId, - query: '' + query: '', }; - tests[`http://form.io/project/${ projectId }/form/${ formId }?test=hello&test2=there`] = { - projectUrl: `http://form.io/project/${ projectId}`, + tests[`http://form.io/project/${projectId}/form/${formId}?test=hello&test2=there`] = { + projectUrl: `http://form.io/project/${projectId}`, projectsUrl: 'http://form.io/project', projectId: projectId, - formsUrl: `http://form.io/project/${ projectId }/form`, - formUrl: `http://form.io/project/${ projectId }/form/${ formId}`, + formsUrl: `http://form.io/project/${projectId}/form`, + formUrl: `http://form.io/project/${projectId}/form/${formId}`, formId: formId, - actionsUrl: `http://form.io/project/${ projectId }/form/${ formId }/action`, + actionsUrl: `http://form.io/project/${projectId}/form/${formId}/action`, actionUrl: '', actionId: '', - submissionsUrl: `http://form.io/project/${ projectId }/form/${ formId }/submission`, + submissionsUrl: `http://form.io/project/${projectId}/form/${formId}/submission`, submissionUrl: '', submissionId: '', - query: '?test=hello&test2=there' + query: '?test=hello&test2=there', }; tests['http://project.form.io/user/login'] = { projectUrl: 'http://project.form.io', @@ -185,9 +191,9 @@ describe('Formio.js Tests', () => { submissionsUrl: 'http://project.form.io/user/login/submission', submissionUrl: '', submissionId: '', - query: '' + query: '', }; - tests[`http://project.form.io/user/login/submission/${ submissionId}`] = { + tests[`http://project.form.io/user/login/submission/${submissionId}`] = { projectUrl: 'http://project.form.io', projectsUrl: `${baseUrl}/project`, projectId: 'project', @@ -198,11 +204,11 @@ describe('Formio.js Tests', () => { actionUrl: '', actionId: '', submissionsUrl: 'http://project.form.io/user/login/submission', - submissionUrl: `http://project.form.io/user/login/submission/${ submissionId}`, + submissionUrl: `http://project.form.io/user/login/submission/${submissionId}`, submissionId: submissionId, - query: '' + query: '', }; - tests[`http://project.form.io/user/login/action/${ actionId}`] = { + tests[`http://project.form.io/user/login/action/${actionId}`] = { projectUrl: 'http://project.form.io', projectsUrl: `${baseUrl}/project`, projectId: 'project', @@ -210,14 +216,14 @@ describe('Formio.js Tests', () => { formUrl: 'http://project.form.io/user/login', formId: 'user/login', actionsUrl: 'http://project.form.io/user/login/action', - actionUrl: `http://project.form.io/user/login/action/${ actionId}`, + actionUrl: `http://project.form.io/user/login/action/${actionId}`, actionId: actionId, submissionsUrl: 'http://project.form.io/user/login/submission', submissionUrl: '', submissionId: '', - query: '' + query: '', }; - tests[`http://project.form.io/user/login/action/${ actionId }?test=test2`] = { + tests[`http://project.form.io/user/login/action/${actionId}?test=test2`] = { projectUrl: 'http://project.form.io', projectsUrl: `${baseUrl}/project`, projectId: 'project', @@ -225,14 +231,14 @@ describe('Formio.js Tests', () => { formUrl: 'http://project.form.io/user/login', formId: 'user/login', actionsUrl: 'http://project.form.io/user/login/action', - actionUrl: `http://project.form.io/user/login/action/${ actionId}`, + actionUrl: `http://project.form.io/user/login/action/${actionId}`, actionId: actionId, submissionsUrl: 'http://project.form.io/user/login/submission', submissionUrl: '', submissionId: '', - query: '?test=test2' + query: '?test=test2', }; - tests[`http://project.form.io/user/loginform/action/${ actionId }?test=test2`] = { + tests[`http://project.form.io/user/loginform/action/${actionId}?test=test2`] = { projectUrl: 'http://project.form.io', projectsUrl: `${baseUrl}/project`, projectId: 'project', @@ -240,12 +246,12 @@ describe('Formio.js Tests', () => { formUrl: 'http://project.form.io/user/loginform', formId: 'user/loginform', actionsUrl: 'http://project.form.io/user/loginform/action', - actionUrl: `http://project.form.io/user/loginform/action/${ actionId}`, + actionUrl: `http://project.form.io/user/loginform/action/${actionId}`, actionId: actionId, submissionsUrl: 'http://project.form.io/user/loginform/submission', submissionUrl: '', submissionId: '', - query: '?test=test2' + query: '?test=test2', }; tests['http://project.form.io/user/loginform/submission'] = { projectUrl: 'http://project.form.io', @@ -260,7 +266,7 @@ describe('Formio.js Tests', () => { submissionsUrl: 'http://project.form.io/user/loginform/submission', submissionUrl: '', submissionId: '', - query: '' + query: '', }; tests['http://project.form.io/user'] = { projectUrl: 'http://project.form.io', @@ -275,9 +281,9 @@ describe('Formio.js Tests', () => { submissionsUrl: 'http://project.form.io/user/submission', submissionUrl: '', submissionId: '', - query: '' + query: '', }; - tests[`http://project.form.io/user/actionform/submission/${ submissionId}`] = { + tests[`http://project.form.io/user/actionform/submission/${submissionId}`] = { projectUrl: 'http://project.form.io', projectsUrl: `${baseUrl}/project`, projectId: 'project', @@ -288,9 +294,9 @@ describe('Formio.js Tests', () => { actionUrl: '', actionId: '', submissionsUrl: 'http://project.form.io/user/actionform/submission', - submissionUrl: `http://project.form.io/user/actionform/submission/${ submissionId}`, + submissionUrl: `http://project.form.io/user/actionform/submission/${submissionId}`, submissionId: submissionId, - query: '' + query: '', }; tests['http://project.form.io/user/actionform/?test=foo'] = { projectUrl: 'http://project.form.io', @@ -305,141 +311,150 @@ describe('Formio.js Tests', () => { submissionsUrl: 'http://project.form.io/user/actionform/submission', submissionUrl: '', submissionId: '', - query: '?test=foo' + query: '?test=foo', }; }); }); - describe('Localhost Constructor Tests', () => { + describe('Localhost Constructor Tests', function () { const testBaseUrl = 'localhost:3000'; const projectName = 'myproject'; const projectUrl = `${protocol}://${projectName}.${testBaseUrl}`; - runTests((tests: any) => { - tests[`${projectUrl}/user/actionform/?test=foo`] = { - projectUrl: projectUrl, - projectsUrl: `${baseUrl}/project`, - projectId: projectName, - formsUrl: `${projectUrl}/form`, - formUrl: `${projectUrl}/user/actionform`, - formId: 'user/actionform', - actionsUrl: `${projectUrl}/user/actionform/action`, - actionUrl: '', - actionId: '', - submissionsUrl: `${projectUrl}/user/actionform/submission`, - submissionUrl: '', - submissionId: '', - query: '?test=foo' - }; - tests[`${projectUrl}/user`] = { - projectUrl: projectUrl, - projectsUrl: `${baseUrl}/project`, - projectId: projectName, - formsUrl: `${projectUrl}/form`, - formUrl: `${projectUrl}/user`, - formId: 'user', - actionsUrl: `${projectUrl}/user/action`, - actionUrl: '', - actionId: '', - submissionsUrl: `${projectUrl}/user/submission`, - submissionUrl: '', - submissionId: '', - query: '' - }; - }, { base: baseUrl }); + runTests( + (tests: any) => { + tests[`${projectUrl}/user/actionform/?test=foo`] = { + projectUrl: projectUrl, + projectsUrl: `${baseUrl}/project`, + projectId: projectName, + formsUrl: `${projectUrl}/form`, + formUrl: `${projectUrl}/user/actionform`, + formId: 'user/actionform', + actionsUrl: `${projectUrl}/user/actionform/action`, + actionUrl: '', + actionId: '', + submissionsUrl: `${projectUrl}/user/actionform/submission`, + submissionUrl: '', + submissionId: '', + query: '?test=foo', + }; + tests[`${projectUrl}/user`] = { + projectUrl: projectUrl, + projectsUrl: `${baseUrl}/project`, + projectId: projectName, + formsUrl: `${projectUrl}/form`, + formUrl: `${projectUrl}/user`, + formId: 'user', + actionsUrl: `${projectUrl}/user/action`, + actionUrl: '', + actionId: '', + submissionsUrl: `${projectUrl}/user/submission`, + submissionUrl: '', + submissionId: '', + query: '', + }; + }, + { base: baseUrl }, + ); }); - describe('Subdomain Constructor Tests', () => { + describe('Subdomain Constructor Tests', function () { const testBaseUrl = 'foo.blah.form.io'; const projectName = 'myproject'; const projectUrl = `${protocol}://${projectName}.${testBaseUrl}`; - runTests((tests: any) => { - tests[`${projectUrl}/user/actionform/?test=foo`] = { - projectUrl: projectUrl, - projectsUrl: `${baseUrl}/project`, - projectId: projectName, - formsUrl: `${projectUrl}/form`, - formUrl: `${projectUrl}/user/actionform`, - formId: 'user/actionform', - actionsUrl: `${projectUrl}/user/actionform/action`, - actionUrl: '', - actionId: '', - submissionsUrl: `${projectUrl}/user/actionform/submission`, - submissionUrl: '', - submissionId: '', - query: '?test=foo' - }; - tests[`${projectUrl}/user`] = { - projectUrl: projectUrl, - projectsUrl: `${baseUrl}/project`, - projectId: projectName, - formsUrl: `${projectUrl}/form`, - formUrl: `${projectUrl}/user`, - formId: 'user', - actionsUrl: `${projectUrl}/user/action`, - actionUrl: '', - actionId: '', - submissionsUrl: `${projectUrl}/user/submission`, - submissionUrl: '', - submissionId: '', - query: '' - }; - }, { base: baseUrl }); + runTests( + (tests: any) => { + tests[`${projectUrl}/user/actionform/?test=foo`] = { + projectUrl: projectUrl, + projectsUrl: `${baseUrl}/project`, + projectId: projectName, + formsUrl: `${projectUrl}/form`, + formUrl: `${projectUrl}/user/actionform`, + formId: 'user/actionform', + actionsUrl: `${projectUrl}/user/actionform/action`, + actionUrl: '', + actionId: '', + submissionsUrl: `${projectUrl}/user/actionform/submission`, + submissionUrl: '', + submissionId: '', + query: '?test=foo', + }; + tests[`${projectUrl}/user`] = { + projectUrl: projectUrl, + projectsUrl: `${baseUrl}/project`, + projectId: projectName, + formsUrl: `${projectUrl}/form`, + formUrl: `${projectUrl}/user`, + formId: 'user', + actionsUrl: `${projectUrl}/user/action`, + actionUrl: '', + actionId: '', + submissionsUrl: `${projectUrl}/user/submission`, + submissionUrl: '', + submissionId: '', + query: '', + }; + }, + { base: baseUrl }, + ); }); - describe('Subdirectory Constructor Tests', () => { + describe('Subdirectory Constructor Tests', function () { const testBaseUrl = 'foo.blah.form.io'; const projectName = 'myproject'; const projectUrl = `${protocol}://${testBaseUrl}/${projectName}`; - runTests((tests: any) => { - tests[`${projectUrl}/user/actionform/?test=foo`] = { - projectUrl: projectUrl, - projectsUrl: `${protocol}://${testBaseUrl}/project`, - projectId: projectName, - formsUrl: `${projectUrl}/form`, - formUrl: `${projectUrl}/user/actionform`, - formId: 'user/actionform', - actionsUrl: `${projectUrl}/user/actionform/action`, - actionUrl: '', - actionId: '', - submissionsUrl: `${projectUrl}/user/actionform/submission`, - submissionUrl: '', - submissionId: '', - query: '?test=foo' - }; - tests[`${projectUrl}/user`] = { - projectUrl: projectUrl, - projectsUrl: `${protocol}://${testBaseUrl}/project`, - projectId: projectName, - formsUrl: `${projectUrl}/form`, - formUrl: `${projectUrl}/user`, - formId: 'user', - actionsUrl: `${projectUrl}/user/action`, - actionUrl: '', - actionId: '', - submissionsUrl: `${projectUrl}/user/submission`, - submissionUrl: '', - submissionId: '', - query: '' - }; - tests[projectUrl] = { - projectUrl: projectUrl, - projectsUrl: `${protocol}://${testBaseUrl}/project`, - projectId: projectName, - formsUrl: `${projectUrl}/form`, - formUrl: '', - formId: '', - actionsUrl: `${projectUrl}/action`, - actionUrl: '', - actionId: '', - submissionsUrl: `${projectUrl}/submission`, - submissionUrl: '', - submissionId: '', - query: '' - }; - }, { base: `${protocol}://${testBaseUrl}` }); + runTests( + (tests: any) => { + tests[`${projectUrl}/user/actionform/?test=foo`] = { + projectUrl: projectUrl, + projectsUrl: `${protocol}://${testBaseUrl}/project`, + projectId: projectName, + formsUrl: `${projectUrl}/form`, + formUrl: `${projectUrl}/user/actionform`, + formId: 'user/actionform', + actionsUrl: `${projectUrl}/user/actionform/action`, + actionUrl: '', + actionId: '', + submissionsUrl: `${projectUrl}/user/actionform/submission`, + submissionUrl: '', + submissionId: '', + query: '?test=foo', + }; + tests[`${projectUrl}/user`] = { + projectUrl: projectUrl, + projectsUrl: `${protocol}://${testBaseUrl}/project`, + projectId: projectName, + formsUrl: `${projectUrl}/form`, + formUrl: `${projectUrl}/user`, + formId: 'user', + actionsUrl: `${projectUrl}/user/action`, + actionUrl: '', + actionId: '', + submissionsUrl: `${projectUrl}/user/submission`, + submissionUrl: '', + submissionId: '', + query: '', + }; + tests[projectUrl] = { + projectUrl: projectUrl, + projectsUrl: `${protocol}://${testBaseUrl}/project`, + projectId: projectName, + formsUrl: `${projectUrl}/form`, + formUrl: '', + formId: '', + actionsUrl: `${projectUrl}/action`, + actionUrl: '', + actionId: '', + submissionsUrl: `${projectUrl}/submission`, + submissionUrl: '', + submissionId: '', + query: '', + }; + }, + { base: `${protocol}://${testBaseUrl}` }, + ); }); - describe('Simple Form Constructor Tests', () => { + describe('Simple Form Constructor Tests', function () { runTests((tests: any) => { tests['init'] = () => { Formio.setBaseUrl('https://api.form.io'); @@ -459,81 +474,108 @@ describe('Formio.js Tests', () => { submissionsUrl: 'https://examples.form.io/example/submission', submissionUrl: '', submissionId: '', - query: '' + query: '', }; return true; }); }); - describe('Open Source Constructor Tests', () => { + describe('Open Source Constructor Tests', function () { const formBaseUrl = 'http://localhost:3000'; - runTests((tests: any) => { - tests[`${formBaseUrl}/user`] = { - projectUrl: formBaseUrl, - projectsUrl: '', - projectId: '', - formsUrl: `${formBaseUrl}/form`, - formUrl: `${formBaseUrl}/user`, - formId: 'user', - actionsUrl: `${formBaseUrl}/user/action`, - actionUrl: '', - actionId: '', - submissionsUrl: `${formBaseUrl}/user/submission`, - submissionUrl: '', - submissionId: '', - query: '' - }; - tests[`${formBaseUrl}/user/actionform/?test=foo`] = { - projectUrl: formBaseUrl, - projectsUrl: '', - projectId: '', - formsUrl: `${formBaseUrl}/form`, - formUrl: `${formBaseUrl}/user/actionform`, - formId: 'user/actionform', - actionsUrl: `${formBaseUrl}/user/actionform/action`, - actionUrl: '', - actionId: '', - submissionsUrl: `${formBaseUrl}/user/actionform/submission`, - submissionUrl: '', - submissionId: '', - query: '?test=foo' - }; - }, { base: formBaseUrl, project: formBaseUrl }); + runTests( + (tests: any) => { + tests[`${formBaseUrl}/user`] = { + projectUrl: formBaseUrl, + projectsUrl: '', + projectId: '', + formsUrl: `${formBaseUrl}/form`, + formUrl: `${formBaseUrl}/user`, + formId: 'user', + actionsUrl: `${formBaseUrl}/user/action`, + actionUrl: '', + actionId: '', + submissionsUrl: `${formBaseUrl}/user/submission`, + submissionUrl: '', + submissionId: '', + query: '', + }; + tests[`${formBaseUrl}/user/actionform/?test=foo`] = { + projectUrl: formBaseUrl, + projectsUrl: '', + projectId: '', + formsUrl: `${formBaseUrl}/form`, + formUrl: `${formBaseUrl}/user/actionform`, + formId: 'user/actionform', + actionsUrl: `${formBaseUrl}/user/actionform/action`, + actionUrl: '', + actionId: '', + submissionsUrl: `${formBaseUrl}/user/actionform/submission`, + submissionUrl: '', + submissionId: '', + query: '?test=foo', + }; + }, + { base: formBaseUrl, project: formBaseUrl }, + ); }); - describe('Plugins', () => { + describe('Plugins', function () { let plugin: any = null; - beforeEach(() => { - assert.equal(Formio.getPlugin('test-plugin'), undefined, 'No plugin may be returned under the name `test-plugin`'); + + beforeEach(function () { + assert.equal( + Formio.getPlugin('test-plugin'), + undefined, + 'No plugin may be returned under the name `test-plugin`', + ); plugin = { init: sinon.spy() }; Formio.registerPlugin(plugin, 'test-plugin'); assert.ok(plugin.init.calledOnce, 'plugin.init must be called exactly once'); assert.ok(plugin.init.calledOn(plugin), 'plugin.init must be called on plugin as `this`'); - assert.ok(plugin.init.calledWithExactly(Formio), 'plugin.init must be given Formio as argument'); + assert.ok( + plugin.init.calledWithExactly(Formio), + 'plugin.init must be given Formio as argument', + ); assert.equal(Formio.getPlugin('test-plugin'), plugin, 'getPlugin must return plugin'); }); - afterEach(() => { + afterEach(function () { assert.equal(Formio.getPlugin('test-plugin'), plugin, 'getPlugin must return plugin'); plugin.deregister = sinon.spy(); Formio.deregisterPlugin(plugin); assert.ok(plugin.deregister.calledOnce, 'plugin.deregister must be called exactly once'); - assert.ok(plugin.deregister.calledOn(plugin), 'plugin.deregister must be called on plugin as `this`'); - assert.ok(plugin.deregister.calledWithExactly(Formio), 'plugin.deregister must be given Formio as argument'); - assert.equal(Formio.getPlugin('test-plugin'), undefined, 'No plugin may be returned under the name `test-plugin`'); + assert.ok( + plugin.deregister.calledOn(plugin), + 'plugin.deregister must be called on plugin as `this`', + ); + assert.ok( + plugin.deregister.calledWithExactly(Formio), + 'plugin.deregister must be given Formio as argument', + ); + assert.equal( + Formio.getPlugin('test-plugin'), + undefined, + 'No plugin may be returned under the name `test-plugin`', + ); }); // Test a request to see if the plugin flow order is correct const testRequest = function testRequest(url: any, method: any, type: any) { let fnName: any; switch (method) { - case 'GET': fnName = `load${capitalize(type)}`; break; + case 'GET': + fnName = `load${capitalize(type)}`; + break; case 'POST': - case 'PUT': fnName = `save${capitalize(type)}`; break; - case 'DELETE': fnName = `delete${capitalize(type)}`; break; + case 'PUT': + fnName = `save${capitalize(type)}`; + break; + case 'DELETE': + fnName = `delete${capitalize(type)}`; + break; } - it(`Plugin ${method} ${fnName}`, (done) => { + it(`Plugin ${method} ${fnName}`, function (done) { let step = 0; const formio: any = new Formio(url); method = method.toUpperCase(); @@ -547,31 +589,41 @@ describe('Formio.js Tests', () => { method: method, url: formio[type + (method === 'POST' ? 'sUrl' : 'Url')], data: startsWith(fnName, 'save') ? testData : null, - opts: testOpts + opts: testOpts, }; // Set up plugin hooks - plugin.preRequest = function(requestArgs: any) { + plugin.preRequest = function (requestArgs: any) { assert.equal(++step, 1, 'preRequest hook should be called first'); - assert.deepEqual(requestArgs, expectedArgs, 'Request hook arguments match expected arguments'); - return Promise.resolve() - .then(() => { - assert.equal(++step, 3, 'preRequest promise should resolve third'); - // TODO - }); + assert.deepEqual( + requestArgs, + expectedArgs, + 'Request hook arguments match expected arguments', + ); + return Promise.resolve().then(() => { + assert.equal(++step, 3, 'preRequest promise should resolve third'); + // TODO + }); }; - plugin.request = function(requestArgs: any) { + plugin.request = function (requestArgs: any) { assert.equal(++step, 4, 'request hook should be called fourth'); - assert.deepEqual(requestArgs, expectedArgs, 'Request hook arguments match expected arguments'); - return Promise.resolve() - .then(() => { - assert.equal(++step, 5, 'request promise should resolve fifth'); - return testResult; - }); + assert.deepEqual( + requestArgs, + expectedArgs, + 'Request hook arguments match expected arguments', + ); + return Promise.resolve().then(() => { + assert.equal(++step, 5, 'request promise should resolve fifth'); + return testResult; + }); }; - plugin.wrapRequestPromise = function(promise: any, requestArgs: any) { + plugin.wrapRequestPromise = function (promise: any, requestArgs: any) { assert.equal(++step, 2, 'wrapRequestPromise hook should be called second'); - assert.deepEqual(requestArgs, expectedArgs, 'Request hook arguments match expected arguments'); + assert.deepEqual( + requestArgs, + expectedArgs, + 'Request hook arguments match expected arguments', + ); return promise.then((result: any) => { assert.equal(++step, 6, 'wrapRequestPromise post-result promise should resolve sixth'); assert.deepEqual(result, testResult, 'Result should match result from request hook'); @@ -582,11 +634,9 @@ describe('Formio.js Tests', () => { let promise; if (startsWith(fnName, 'save')) { promise = formio[fnName](testData, testOpts); - } - else if (startsWith(fnName, 'load')) { + } else if (startsWith(fnName, 'load')) { promise = formio[fnName](null, testOpts); - } - else { + } else { promise = formio[fnName](testOpts); } promise.then((result: any) => { @@ -601,106 +651,106 @@ describe('Formio.js Tests', () => { { url: 'https://api.localhost:3000/project/myproject', method: 'GET', - type: 'project' + type: 'project', }, { url: '', method: 'POST', - type: 'project' + type: 'project', }, { url: 'https://api.localhost:3000/project/myproject', method: 'PUT', - type: 'project' + type: 'project', }, { url: 'https://api.localhost:3000/project/myproject', method: 'DELETE', - type: 'project' + type: 'project', }, { url: 'https://api.localhost:3000/project/myproject/form/0123456789ABCDEF01234567', method: 'GET', - type: 'form' + type: 'form', }, { url: 'https://api.localhost:3000/project/myproject', method: 'POST', - type: 'form' + type: 'form', }, { url: 'https://api.localhost:3000/project/myproject/form/0123456789ABCDEF01234567', method: 'PUT', - type: 'form' + type: 'form', }, { url: '/project/myproject/form/0123456789ABCDEF01234567', method: 'PUT', - type: 'form' + type: 'form', }, { url: 'https://api.localhost:3000/project/myproject/form/0123456789ABCDEF01234567', method: 'DELETE', - type: 'form' + type: 'form', }, { url: 'https://api.localhost:3000/project/myproject/', method: 'GET', - type: 'forms' + type: 'forms', }, { url: 'https://api.localhost:3000/project/myproject/form/0123456789ABCDEF01234567/submission/76543210FEDCBA9876543210', method: 'GET', - type: 'submission' + type: 'submission', }, { url: 'https://api.localhost:3000/project/myproject/form/0123456789ABCDEF01234567', method: 'POST', - type: 'submission' + type: 'submission', }, { url: 'https://api.localhost:3000/project/myproject/form/0123456789ABCDEF01234567/submission/76543210FEDCBA9876543210', method: 'PUT', - type: 'submission' + type: 'submission', }, { url: 'https://api.localhost:3000/project/myproject/form/0123456789ABCDEF01234567/submission/76543210FEDCBA9876543210', method: 'DELETE', - type: 'submission' + type: 'submission', }, { url: 'https://api.localhost:3000/project/myproject/form/0123456789ABCDEF01234567', method: 'GET', - type: 'submissions' + type: 'submissions', }, { url: 'https://api.localhost:3000/project/myproject/form/0123456789ABCDEF01234567/action/76543210FEDCBA9876543210', method: 'GET', - type: 'action' + type: 'action', }, { url: 'https://api.localhost:3000/project/myproject/form/0123456789ABCDEF01234567', method: 'POST', - type: 'action' + type: 'action', }, { url: 'https://api.localhost:3000/project/myproject/form/0123456789ABCDEF01234567/action/76543210FEDCBA9876543210', method: 'PUT', - type: 'action' + type: 'action', }, { url: 'https://api.localhost:3000/project/myproject/form/0123456789ABCDEF01234567/action/76543210FEDCBA9876543210', method: 'DELETE', - type: 'action' + type: 'action', }, { url: 'https://api.localhost:3000/project/myproject/form/0123456789ABCDEF01234567', method: 'GET', - type: 'actions' - } + type: 'actions', + }, ]; tests.forEach((test) => { @@ -708,38 +758,48 @@ describe('Formio.js Tests', () => { }); const testStaticRequest = function testStaticRequest(fnName: any, url: any, method: any) { - it(`Plugin ${fnName}`, (done) => { + it(`Plugin ${fnName}`, function (done) { let step = 0; const testResult = { _id: 'TEST_ID', testResult: 'TEST_RESULT' }; const expectedArgs = { url: url, method: method, data: null, - opts: {} + opts: {}, }; // Set up plugin hooks - plugin.preRequest = function(requestArgs: any) { + plugin.preRequest = function (requestArgs: any) { assert.equal(++step, 1, 'preRequest hook should be called first'); - assert.deepEqual(requestArgs, expectedArgs, 'Request hook arguments match expected arguments'); - return Promise.resolve() - .then(() => { - assert.equal(++step, 3, 'preRequest promise should resolve third'); - // TODO - }); + assert.deepEqual( + requestArgs, + expectedArgs, + 'Request hook arguments match expected arguments', + ); + return Promise.resolve().then(() => { + assert.equal(++step, 3, 'preRequest promise should resolve third'); + // TODO + }); }; - plugin.staticRequest = function(requestArgs: any) { + plugin.staticRequest = function (requestArgs: any) { assert.equal(++step, 4, 'request hook should be called fourth'); - assert.deepEqual(requestArgs, expectedArgs, 'Request hook arguments match expected arguments'); - return Promise.resolve() - .then(() => { - assert.equal(++step, 5, 'request promise should resolve fifth'); - return testResult; - }); + assert.deepEqual( + requestArgs, + expectedArgs, + 'Request hook arguments match expected arguments', + ); + return Promise.resolve().then(() => { + assert.equal(++step, 5, 'request promise should resolve fifth'); + return testResult; + }); }; - plugin.wrapStaticRequestPromise = function(promise: any, requestArgs: any) { + plugin.wrapStaticRequestPromise = function (promise: any, requestArgs: any) { assert.equal(++step, 2, 'wrapRequestPromise hook should be called second'); - assert.deepEqual(requestArgs, expectedArgs, 'Request hook arguments match expected arguments'); + assert.deepEqual( + requestArgs, + expectedArgs, + 'Request hook arguments match expected arguments', + ); return promise.then((result: any) => { assert.equal(++step, 6, 'wrapRequestPromise post-result promise should resolve sixth'); assert.deepEqual(result, testResult, 'Result should match result from request hook'); @@ -747,12 +807,11 @@ describe('Formio.js Tests', () => { }); }; - (Formio as any)[fnName]() - .then((result: any) => { - assert.equal(++step, 7, 'post request promise should resolve last'); - assert.deepEqual(result, testResult, 'Result should match result from request hook'); - done(); - }); + (Formio as any)[fnName]().then((result: any) => { + assert.equal(++step, 7, 'post request promise should resolve last'); + assert.deepEqual(result, testResult, 'Result should match result from request hook'); + done(); + }); }); }; @@ -760,13 +819,13 @@ describe('Formio.js Tests', () => { { fnName: 'loadProjects', url: 'https://api.localhost:3000/project', - method: 'GET' + method: 'GET', }, { fnName: 'logout', url: 'https://api.localhost:3000/logout', - method: 'GET' - } + method: 'GET', + }, ]; staticTests.forEach((test) => { @@ -774,9 +833,9 @@ describe('Formio.js Tests', () => { }); }); - describe('Test Formio.js capabilities', () => { - const testCapability = function(test: any) { - it(test.name, (done) => { + describe('Test Formio.js capabilities', function () { + const testCapability = function (test: any) { + it(test.name, function (done) { // need to clear Formio cache before every test, otherwise mock results might be ignored for same URLs Formio.clearCache(); if (test.mock) { @@ -785,8 +844,7 @@ describe('Formio.js Tests', () => { each(mock, (_mock) => { fetchMock.mock(_mock.url, _mock.response, { method: _mock.method }); }); - } - else { + } else { fetchMock.mock(mock.url, mock.response, { method: mock.method }); } } @@ -825,19 +883,18 @@ describe('Formio.js Tests', () => { data: { 'user.name': chance.string({ length: 10, - pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' + pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', }), 'user.email': chance.email(), - 'user.password': chance.string({ length: 12 }) - } + 'user.password': chance.string({ length: 12 }), + }, }; Formio.setProjectUrl(Formio.getBaseUrl()); const formio = new Formio(`${Formio.getBaseUrl()}/user/register`); - return formio.saveSubmission(req) - .then((response: any) => { - assert.deepEqual(response, user, 'saveSubmission response should match test user'); - assert.equal(Formio.getToken(), userToken, 'Formio should save the user token'); - }); + return formio.saveSubmission(req).then((response: any) => { + assert.deepEqual(response, user, 'saveSubmission response should match test user'); + assert.equal(Formio.getToken(), userToken, 'Formio should save the user token'); + }); }, mock() { return [ @@ -848,11 +905,11 @@ describe('Formio.js Tests', () => { return { headers: { 'Content-Type': 'application/json', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: user + body: user, }; - } + }, }, { url: `${Formio.getBaseUrl()}/user/register/submission`, @@ -866,25 +923,25 @@ describe('Formio.js Tests', () => { modified: new Date().toISOString(), data: { email: body.data['user.email'], - name: body.data['user.name'] + name: body.data['user.name'], }, externalIds: [], externalTokens: [], form: userFormId, - owner: userId + owner: userId, }; userPassword = body.data['user.password']; return { headers: { 'Content-Type': 'application/json', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: user + body: user, }; - } - } + }, + }, ]; - } + }, }, { name: 'Logging in.', @@ -892,15 +949,14 @@ describe('Formio.js Tests', () => { const req = { data: { 'user.email': user.data.email, - 'user.password': userPassword - } + 'user.password': userPassword, + }, }; const formio = new Formio(`${Formio.getBaseUrl()}/user/login`); - return formio.saveSubmission(req) - .then((response: any) => { - assert.deepEqual(response, user, 'saveSubmission response should match test user'); - assert.equal(Formio.getToken(), userToken, 'Formio should save the user token'); - }); + return formio.saveSubmission(req).then((response: any) => { + assert.deepEqual(response, user, 'saveSubmission response should match test user'); + assert.equal(Formio.getToken(), userToken, 'Formio should save the user token'); + }); }, mock() { return { @@ -909,18 +965,26 @@ describe('Formio.js Tests', () => { response(url: any, opts: any) { const body = JSON.parse(opts.body); userToken = chance.string({ length: 450 }); - assert.equal(body.data['user.email'], user.data.email, 'Login email must be correct.'); - assert.equal(body.data['user.password'], userPassword, 'Login password must be correct.'); + assert.equal( + body.data['user.email'], + user.data.email, + 'Login email must be correct.', + ); + assert.equal( + body.data['user.password'], + userPassword, + 'Login password must be correct.', + ); return { headers: { 'Content-Type': 'application/json', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: user + body: user, }; - } + }, }; - } + }, }, { name: 'Current user.', @@ -945,13 +1009,13 @@ describe('Formio.js Tests', () => { return { headers: { 'Content-Type': 'application/json', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: user + body: user, }; - } + }, }; - } + }, }, { name: 'Create Project', @@ -960,22 +1024,21 @@ describe('Formio.js Tests', () => { const req = { title: chance.string({ length: 10, - pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' + pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', }), name: chance.string({ length: 10, - pool: 'abcdefghijklmnopqrstuvwxyz' + pool: 'abcdefghijklmnopqrstuvwxyz', }), description: chance.paragraph({ sentences: 1 }), settings: { - cors: '*' + cors: '*', }, - template: 'http://help.form.io/templates/empty.json' + template: 'http://help.form.io/templates/empty.json', }; - return formio.saveProject(req) - .then((response: any) => { - assert.deepEqual(response, project, 'saveProject response should match test user'); - }); + return formio.saveProject(req).then((response: any) => { + assert.deepEqual(response, project, 'saveProject response should match test user'); + }); }, mock() { return { @@ -992,37 +1055,36 @@ describe('Formio.js Tests', () => { used: 0, limit: 1000, remaining: 1000, - reset: new Date(Date.now() + 2.628e9).toISOString() // ~1 month later + reset: new Date(Date.now() + 2.628e9).toISOString(), // ~1 month later }, access: [], title: body.title, name: body.name, description: body.description, plan: 'basic', - owner: user._id + owner: user._id, }; return { headers: { 'Content-Type': 'application/json', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: project + body: project, }; - } + }, }; - } + }, }, { name: 'Getting Projects', test() { - return Formio.loadProjects() - .then((projects: any) => { - assert.equal(projects.length, 1, 'Should return only one project.'); - assert.equal(projects.skip, 0, 'skip should be 0.'); - assert.equal(projects.limit, 1, 'limit should be 1.'); - assert.equal(projects.serverCount, 1, 'serverCount should be 1.'); - assert.deepEqual(projects[0], project, 'Should match project'); - }); + return Formio.loadProjects().then((projects: any) => { + assert.equal(projects.length, 1, 'Should return only one project.'); + assert.equal(projects.skip, 0, 'skip should be 0.'); + assert.equal(projects.limit, 1, 'limit should be 1.'); + assert.equal(projects.serverCount, 1, 'serverCount should be 1.'); + assert.deepEqual(projects[0], project, 'Should match project'); + }); }, mock() { return { @@ -1034,22 +1096,21 @@ describe('Formio.js Tests', () => { 'Content-Type': 'application/json', 'Content-Range': '0-0/1', 'Range-Unit': 'items', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: [project] + body: [project], }; - } + }, }; - } + }, }, { name: 'Read Project', test() { const formio = new Formio(`${Formio.getBaseUrl()}/project/${project._id}`); - return formio.loadProject() - .then((response: any) => { - assert.deepEqual(response, project, 'Should match project'); - }); + return formio.loadProject().then((response: any) => { + assert.deepEqual(response, project, 'Should match project'); + }); }, mock() { return { @@ -1059,13 +1120,13 @@ describe('Formio.js Tests', () => { return { headers: { 'Content-Type': 'application/json', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: project + body: project, }; - } + }, }; - } + }, }, { name: 'Update Project', @@ -1074,17 +1135,16 @@ describe('Formio.js Tests', () => { const newProject = fastCloneDeep(project); newProject.name = chance.string({ length: 10, - pool: 'abcdefghijklmnopqrstuvwxyz' + pool: 'abcdefghijklmnopqrstuvwxyz', }); newProject.title = chance.string({ length: 10, - pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' + pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', }); newProject.description = chance.paragraph({ sentences: 1 }); - return formio.saveProject(newProject) - .then((response: any) => { - assert.deepEqual(response, project, 'Project should match'); - }); + return formio.saveProject(newProject).then((response: any) => { + assert.deepEqual(response, project, 'Project should match'); + }); }, mock() { return { @@ -1096,13 +1156,13 @@ describe('Formio.js Tests', () => { return { headers: { 'Content-Type': 'application/json', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: project + body: project, }; - } + }, }; - } + }, }, { name: 'Create Form', @@ -1111,15 +1171,15 @@ describe('Formio.js Tests', () => { const req = { title: chance.string({ length: 10, - pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' + pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', }), name: chance.string({ length: 10, - pool: 'abcdefghijklmnopqrstuvwxyz' + pool: 'abcdefghijklmnopqrstuvwxyz', }), path: chance.string({ length: 10, - pool: 'abcdefghijklmnopqrstuvwxyz' + pool: 'abcdefghijklmnopqrstuvwxyz', }), components: [ { @@ -1145,8 +1205,8 @@ describe('Formio.js Tests', () => { maxLength: '', pattern: '', custom: '', - customPrivate: false - } + customPrivate: false, + }, }, { action: 'submit', @@ -1160,17 +1220,16 @@ describe('Formio.js Tests', () => { size: 'md', tableView: false, theme: 'primary', - type: 'button' - } + type: 'button', + }, ], type: 'form', access: [], - submissionAccess: [] + submissionAccess: [], }; - return formio.saveForm(req) - .then((response: any) => { - assert.deepEqual(response, form, 'Form should match'); - }); + return formio.saveForm(req).then((response: any) => { + assert.deepEqual(response, form, 'Form should match'); + }); }, mock() { return { @@ -1185,31 +1244,30 @@ describe('Formio.js Tests', () => { created: new Date().toISOString(), modified: new Date().toISOString(), project: project._id, - owner: user._id + owner: user._id, }); return { headers: { 'Content-Type': 'application/json', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: form + body: form, }; - } + }, }; - } + }, }, { name: 'Load Forms', test() { const formio = new Formio(`/project/${project._id}/form`); - return formio.loadForms() - .then((forms: any) => { - assert.equal(forms.length, 1, 'Should return only one form.'); - assert.equal(forms.skip, 0, 'skip should be 0.'); - assert.equal(forms.limit, 1, 'limit should be 1.'); - assert.equal(forms.serverCount, 1, 'serverCount should be 1.'); - assert.deepEqual(forms[0], form, 'Should match form'); - }); + return formio.loadForms().then((forms: any) => { + assert.equal(forms.length, 1, 'Should return only one form.'); + assert.equal(forms.skip, 0, 'skip should be 0.'); + assert.equal(forms.limit, 1, 'limit should be 1.'); + assert.equal(forms.serverCount, 1, 'serverCount should be 1.'); + assert.deepEqual(forms[0], form, 'Should match form'); + }); }, mock() { return { @@ -1221,22 +1279,21 @@ describe('Formio.js Tests', () => { 'Content-Type': 'application/json', 'Content-Range': '0-0/1', 'Range-Unit': 'items', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: [form] + body: [form], }; - } + }, }; - } + }, }, { name: 'Read Form', test() { const formio = new Formio(`/project/${project._id}/form/${form._id}`); - return formio.loadForm() - .then((response: any) => { - assert.deepEqual(response, form, 'Form should match'); - }); + return formio.loadForm().then((response: any) => { + assert.deepEqual(response, form, 'Form should match'); + }); }, mock() { return { @@ -1246,13 +1303,13 @@ describe('Formio.js Tests', () => { return { headers: { 'Content-Type': 'application/json', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: form + body: form, }; - } + }, }; - } + }, }, { name: 'Update Form', @@ -1261,20 +1318,19 @@ describe('Formio.js Tests', () => { const newForm = fastCloneDeep(form); newForm.title = chance.string({ length: 10, - pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' + pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', }); newForm.name = chance.string({ length: 10, - pool: 'abcdefghijklmnopqrstuvwxyz' + pool: 'abcdefghijklmnopqrstuvwxyz', }); newForm.path = chance.string({ length: 10, - pool: 'abcdefghijklmnopqrstuvwxyz' + pool: 'abcdefghijklmnopqrstuvwxyz', + }); + return formio.saveForm(newForm).then((response: any) => { + assert.deepEqual(response, form, 'Form should match'); }); - return formio.saveForm(newForm) - .then((response: any) => { - assert.deepEqual(response, form, 'Form should match'); - }); }, mock() { return { @@ -1286,13 +1342,13 @@ describe('Formio.js Tests', () => { return { headers: { 'Content-Type': 'application/json', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: form + body: form, }; - } + }, }; - } + }, }, { name: 'Create Submission', @@ -1300,13 +1356,12 @@ describe('Formio.js Tests', () => { const formio = new Formio(`/project/${project._id}/form/${form._id}/submission`); const req = { data: { - fieldLabel: chance.string() - } + fieldLabel: chance.string(), + }, }; - return formio.saveSubmission(req) - .then((response: any) => { - assert.deepEqual(response, submission, 'Submission should match'); - }); + return formio.saveSubmission(req).then((response: any) => { + assert.deepEqual(response, submission, 'Submission should match'); + }); }, mock() { return { @@ -1324,31 +1379,30 @@ describe('Formio.js Tests', () => { externalTokens: [], form: form._id, owner: user._id, - roles: [] + roles: [], }; return { headers: { 'Content-Type': 'application/json', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: submission + body: submission, }; - } + }, }; - } + }, }, { name: 'Load Submissions', test() { const formio = new Formio(`/project/${project._id}/form/${form._id}/submission`); - return formio.loadSubmissions() - .then((submissions: any) => { - assert.equal(submissions.length, 1, 'Should return only one submission.'); - assert.equal(submissions.skip, 0, 'skip should be 0.'); - assert.equal(submissions.limit, 1, 'limit should be 1.'); - assert.equal(submissions.serverCount, 1, 'serverCount should be 1.'); - assert.deepEqual(submissions[0], submission, 'Should match submission'); - }); + return formio.loadSubmissions().then((submissions: any) => { + assert.equal(submissions.length, 1, 'Should return only one submission.'); + assert.equal(submissions.skip, 0, 'skip should be 0.'); + assert.equal(submissions.limit, 1, 'limit should be 1.'); + assert.equal(submissions.serverCount, 1, 'serverCount should be 1.'); + assert.deepEqual(submissions[0], submission, 'Should match submission'); + }); }, mock() { return { @@ -1360,22 +1414,23 @@ describe('Formio.js Tests', () => { 'Content-Type': 'application/json', 'Content-Range': '0-0/1', 'Range-Unit': 'items', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: [submission] + body: [submission], }; - } + }, }; - } + }, }, { name: 'Read Submission', test() { - const formio = new Formio(`/project/${project._id}/form/${form._id}/submission/${submission._id}`); - return formio.loadSubmission() - .then((response: any) => { - assert.deepEqual(response, submission, 'Submission should match'); - }); + const formio = new Formio( + `/project/${project._id}/form/${form._id}/submission/${submission._id}`, + ); + return formio.loadSubmission().then((response: any) => { + assert.deepEqual(response, submission, 'Submission should match'); + }); }, mock() { return { @@ -1385,24 +1440,25 @@ describe('Formio.js Tests', () => { return { headers: { 'Content-Type': 'application/json', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: submission + body: submission, }; - } + }, }; - } + }, }, { name: 'Update Submission', test() { - const formio = new Formio(`/project/${project._id}/form/${form._id}/submission/${submission._id}`); + const formio = new Formio( + `/project/${project._id}/form/${form._id}/submission/${submission._id}`, + ); const newSubmission = fastCloneDeep(submission); newSubmission.data.fieldLabel = chance.string(); - return formio.saveSubmission(newSubmission) - .then((response: any) => { - assert.deepEqual(response, submission, 'Submission should match'); - }); + return formio.saveSubmission(newSubmission).then((response: any) => { + assert.deepEqual(response, submission, 'Submission should match'); + }); }, mock() { return { @@ -1414,13 +1470,13 @@ describe('Formio.js Tests', () => { return { headers: { 'Content-Type': 'application/json', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: submission + body: submission, }; - } + }, }; - } + }, }, { name: 'Update Submission without ID', @@ -1428,10 +1484,9 @@ describe('Formio.js Tests', () => { const formio = new Formio(`/project/${project._id}/form/${form._id}`); const newSubmission = fastCloneDeep(submission); newSubmission.data.fieldLabel = chance.string(); - return formio.saveSubmission(newSubmission) - .then((response: any) => { - assert.deepEqual(response, submission, 'Submission should match'); - }); + return formio.saveSubmission(newSubmission).then((response: any) => { + assert.deepEqual(response, submission, 'Submission should match'); + }); }, mock() { return { @@ -1443,13 +1498,13 @@ describe('Formio.js Tests', () => { return { headers: { 'Content-Type': 'application/json', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: submission + body: submission, }; - } + }, }; - } + }, }, // // Actions // // Available Actions @@ -1457,11 +1512,12 @@ describe('Formio.js Tests', () => { { name: 'Delete Submission', test() { - const formio = new Formio(`/project/${project._id}/form/${form._id}/submission/${submission._id}`); - return formio.deleteSubmission() - .then((response: any) => { - assert.equal(response, 'OK', 'Submission should be deleted.'); - }); + const formio = new Formio( + `/project/${project._id}/form/${form._id}/submission/${submission._id}`, + ); + return formio.deleteSubmission().then((response: any) => { + assert.equal(response, 'OK', 'Submission should be deleted.'); + }); }, mock() { return { @@ -1472,20 +1528,19 @@ describe('Formio.js Tests', () => { body: 'OK', headers: { 'Content-Type': 'text/plain; charset=utf-8', - 'x-jwt-token': userToken - } - } + 'x-jwt-token': userToken, + }, + }, }; - } + }, }, { name: 'Delete Form', test() { const formio = new Formio(`/project/${project._id}/form/${form._id}`); - return formio.deleteForm() - .then((response: any) => { - assert.equal(response, 'OK', 'Submission should be deleted.'); - }); + return formio.deleteForm().then((response: any) => { + assert.equal(response, 'OK', 'Submission should be deleted.'); + }); }, mock() { return { @@ -1496,20 +1551,19 @@ describe('Formio.js Tests', () => { body: 'OK', headers: { 'Content-Type': 'text/plain; charset=utf-8', - 'x-jwt-token': userToken - } - } + 'x-jwt-token': userToken, + }, + }, }; - } + }, }, { name: 'Delete Project', test() { const formio = new Formio(`/project/${project._id}`); - return formio.deleteProject() - .then((response: any) => { - assert.equal(response, 'OK', 'Submission should be deleted.'); - }); + return formio.deleteProject().then((response: any) => { + assert.equal(response, 'OK', 'Submission should be deleted.'); + }); }, mock() { return { @@ -1520,22 +1574,21 @@ describe('Formio.js Tests', () => { body: 'OK', headers: { 'Content-Type': 'text/plain; charset=utf-8', - 'x-jwt-token': userToken - } - } + 'x-jwt-token': userToken, + }, + }, }; - } + }, }, { name: 'Getting Projects', test() { - return Formio.loadProjects() - .then((projects: any) => { - assert.equal(projects.length, 0, 'Should return no projects.'); - assert.equal(projects.skip, undefined, 'skip should be undefined.'); - assert.equal(projects.limit, undefined, 'limit should be undefined.'); - assert.equal(projects.serverCount, 0, 'serverCount should be 0.'); - }); + return Formio.loadProjects().then((projects: any) => { + assert.equal(projects.length, 0, 'Should return no projects.'); + assert.equal(projects.skip, undefined, 'skip should be undefined.'); + assert.equal(projects.limit, undefined, 'limit should be undefined.'); + assert.equal(projects.serverCount, 0, 'serverCount should be 0.'); + }); }, mock() { return { @@ -1547,13 +1600,13 @@ describe('Formio.js Tests', () => { 'Content-Type': 'application/json', 'Content-Range': '*/0', 'Range-Unit': 'items', - 'x-jwt-token': userToken + 'x-jwt-token': userToken, }, - body: [] + body: [], }; - } + }, }; - } + }, }, { name: 'Temporary Token', @@ -1573,20 +1626,19 @@ describe('Formio.js Tests', () => { body: userToken, headers: { 'Content-Type': 'text/plain; charset=utf-8', - 'x-jwt-token': userToken - } + 'x-jwt-token': userToken, + }, }; - } + }, }; - } + }, }, { name: 'Logging Out', test() { - return Formio.logout() - .then(() => { - assert.equal(Formio.getToken(), '', 'Logged out'); - }); + return Formio.logout().then(() => { + assert.equal(Formio.getToken(), '', 'Logged out'); + }); }, mock() { return { @@ -1599,29 +1651,28 @@ describe('Formio.js Tests', () => { body: 'OK', headers: { 'Content-Type': 'text/plain; charset=utf-8', - 'x-jwt-token': '' - } + 'x-jwt-token': '', + }, }; - } + }, }; - } + }, }, { name: 'userPermissions method should give create_all permission', test() { const user = { _id: 'test_user_id', - roles: ['test_role_id'] + roles: ['test_role_id'], }; const formio = new Formio(`${Formio.getBaseUrl()}/testform`); - return formio.userPermissions(user) - .then(permissions => { - assert.equal(permissions.create, true); - assert.equal(permissions.edit, false); - assert.equal(permissions.delete, false); - assert.equal(permissions.read, false); - }); + return formio.userPermissions(user).then((permissions) => { + assert.equal(permissions.create, true); + assert.equal(permissions.edit, false); + assert.equal(permissions.delete, false); + assert.equal(permissions.read, false); + }); }, mock() { return [ @@ -1635,12 +1686,12 @@ describe('Formio.js Tests', () => { submissionAccess: [ { type: 'create_all', - roles: ['test_role_id'] - } - ] + roles: ['test_role_id'], + }, + ], }, }; - } + }, }, { url: `${Formio.getBaseUrl()}/access`, @@ -1649,13 +1700,13 @@ describe('Formio.js Tests', () => { return { status: 200, body: { - roles: [] - } + roles: [], + }, }; - } + }, }, ]; - } + }, }, { name: 'userPermissions method should give create_own permission', @@ -1663,19 +1714,18 @@ describe('Formio.js Tests', () => { const userId = 'test_user_id'; const user = { _id: userId, - roles: ['test_role_id'] + roles: ['test_role_id'], }; const submission = { - owner: userId + owner: userId, }; const formio = new Formio(`${Formio.getBaseUrl()}/testform`); - return formio.userPermissions(user, undefined, submission) - .then(permissions => { - assert.equal(permissions.create, true); - assert.equal(permissions.edit, false); - assert.equal(permissions.read, false); - assert.equal(permissions.delete, false); - }); + return formio.userPermissions(user, undefined, submission).then((permissions) => { + assert.equal(permissions.create, true); + assert.equal(permissions.edit, false); + assert.equal(permissions.read, false); + assert.equal(permissions.delete, false); + }); }, mock() { return [ @@ -1689,12 +1739,12 @@ describe('Formio.js Tests', () => { submissionAccess: [ { type: 'create_own', - roles: ['test_role_id'] - } - ] + roles: ['test_role_id'], + }, + ], }, }; - } + }, }, { url: `${Formio.getBaseUrl()}/access`, @@ -1703,13 +1753,13 @@ describe('Formio.js Tests', () => { return { status: 200, body: { - roles: [] - } + roles: [], + }, }; - } + }, }, ]; - } + }, }, { name: 'userPermissions method should give permissions for Anonymous role', @@ -1719,13 +1769,12 @@ describe('Formio.js Tests', () => { roles: [], }; const formio = new Formio(`${Formio.getBaseUrl()}/testform`); - return formio.userPermissions(user) - .then(permissions => { - assert.equal(permissions.create, true); - assert.equal(permissions.edit, false); - assert.equal(permissions.read, false); - assert.equal(permissions.delete, false); - }); + return formio.userPermissions(user).then((permissions) => { + assert.equal(permissions.create, true); + assert.equal(permissions.edit, false); + assert.equal(permissions.read, false); + assert.equal(permissions.delete, false); + }); }, mock() { return [ @@ -1739,12 +1788,12 @@ describe('Formio.js Tests', () => { submissionAccess: [ { type: 'create_all', - roles: ['test_anonymous_role_id'] - } - ] + roles: ['test_anonymous_role_id'], + }, + ], }, }; - } + }, }, { url: `${Formio.getBaseUrl()}/access`, @@ -1756,15 +1805,15 @@ describe('Formio.js Tests', () => { roles: [ { _id: 'test_anonymous_role_id', - default: true - } - ] - } + default: true, + }, + ], + }, }; - } + }, }, ]; - } + }, }, { name: 'userPermissions method should give all permissions for admin role', @@ -1773,13 +1822,12 @@ describe('Formio.js Tests', () => { roles: ['test_admin_role'], }; const formio = new Formio(`${Formio.getBaseUrl()}/testform`); - return formio.userPermissions(user) - .then(permissions => { - assert.equal(permissions.create, true); - assert.equal(permissions.read, true); - assert.equal(permissions.edit, true); - assert.equal(permissions.delete, true); - }); + return formio.userPermissions(user).then((permissions) => { + assert.equal(permissions.create, true); + assert.equal(permissions.read, true); + assert.equal(permissions.edit, true); + assert.equal(permissions.delete, true); + }); }, mock() { return [ @@ -1790,10 +1838,10 @@ describe('Formio.js Tests', () => { return { status: 200, body: { - submissionAccess: [] + submissionAccess: [], }, }; - } + }, }, { url: `${Formio.getBaseUrl()}/access`, @@ -1805,15 +1853,15 @@ describe('Formio.js Tests', () => { roles: [ { _id: 'test_admin_role', - admin: true - } - ] - } + admin: true, + }, + ], + }, }; - } + }, }, ]; - } + }, }, { name: 'userPermissions method should give only group read permission for `read` level', @@ -1824,18 +1872,17 @@ describe('Formio.js Tests', () => { const submission = { data: { groupField: { - _id: 'test_group_id' - } - } + _id: 'test_group_id', + }, + }, }; const formio = new Formio(`${Formio.getBaseUrl()}/testform`); - return formio.userPermissions(user, undefined, submission) - .then(permissions => { - assert.equal(permissions.create, false); - assert.equal(permissions.read, true); - assert.equal(permissions.edit, false); - assert.equal(permissions.delete, false); - }); + return formio.userPermissions(user, undefined, submission).then((permissions) => { + assert.equal(permissions.create, false); + assert.equal(permissions.read, true); + assert.equal(permissions.edit, false); + assert.equal(permissions.delete, false); + }); }, mock() { return [ @@ -1850,12 +1897,12 @@ describe('Formio.js Tests', () => { components: [ { defaultPermission: 'read', - key: 'groupField' - } - ] + key: 'groupField', + }, + ], }, }; - } + }, }, { url: `${Formio.getBaseUrl()}/access`, @@ -1864,13 +1911,13 @@ describe('Formio.js Tests', () => { return { status: 200, body: { - roles: [] - } + roles: [], + }, }; - } + }, }, ]; - } + }, }, { name: 'userPermissions method should give group read and create permissions for `create` level', @@ -1881,18 +1928,17 @@ describe('Formio.js Tests', () => { const submission = { data: { groupField: { - _id: 'test_group_id' - } - } + _id: 'test_group_id', + }, + }, }; const formio = new Formio(`${Formio.getBaseUrl()}/testform`); - return formio.userPermissions(user, undefined, submission) - .then(permissions => { - assert.equal(permissions.create, true); - assert.equal(permissions.read, true); - assert.equal(permissions.edit, false); - assert.equal(permissions.delete, false); - }); + return formio.userPermissions(user, undefined, submission).then((permissions) => { + assert.equal(permissions.create, true); + assert.equal(permissions.read, true); + assert.equal(permissions.edit, false); + assert.equal(permissions.delete, false); + }); }, mock() { return [ @@ -1907,12 +1953,12 @@ describe('Formio.js Tests', () => { components: [ { defaultPermission: 'create', - key: 'groupField' - } - ] + key: 'groupField', + }, + ], }, }; - } + }, }, { url: `${Formio.getBaseUrl()}/access`, @@ -1921,13 +1967,13 @@ describe('Formio.js Tests', () => { return { status: 200, body: { - roles: [] - } + roles: [], + }, }; - } + }, }, ]; - } + }, }, { name: 'userPermissions method should give group read, create and edit permissions for `write` level', @@ -1938,18 +1984,17 @@ describe('Formio.js Tests', () => { const submission = { data: { groupField: { - _id: 'test_group_id' - } - } + _id: 'test_group_id', + }, + }, }; const formio = new Formio(`${Formio.getBaseUrl()}/testform`); - return formio.userPermissions(user, undefined, submission) - .then(permissions => { - assert.equal(permissions.create, true); - assert.equal(permissions.read, true); - assert.equal(permissions.edit, true); - assert.equal(permissions.delete, false); - }); + return formio.userPermissions(user, undefined, submission).then((permissions) => { + assert.equal(permissions.create, true); + assert.equal(permissions.read, true); + assert.equal(permissions.edit, true); + assert.equal(permissions.delete, false); + }); }, mock() { return [ @@ -1964,12 +2009,12 @@ describe('Formio.js Tests', () => { components: [ { defaultPermission: 'write', - key: 'groupField' - } - ] + key: 'groupField', + }, + ], }, }; - } + }, }, { url: `${Formio.getBaseUrl()}/access`, @@ -1978,13 +2023,13 @@ describe('Formio.js Tests', () => { return { status: 200, body: { - roles: [] - } + roles: [], + }, }; - } + }, }, ]; - } + }, }, { name: 'userPermissions method should give all group permissions for `admin` level', @@ -1995,18 +2040,17 @@ describe('Formio.js Tests', () => { const submission = { data: { groupField: { - _id: 'test_group_id' - } - } + _id: 'test_group_id', + }, + }, }; const formio = new Formio(`${Formio.getBaseUrl()}/testform`); - return formio.userPermissions(user, undefined, submission) - .then(permissions => { - assert.equal(permissions.create, true); - assert.equal(permissions.read, true); - assert.equal(permissions.edit, true); - assert.equal(permissions.delete, true); - }); + return formio.userPermissions(user, undefined, submission).then((permissions) => { + assert.equal(permissions.create, true); + assert.equal(permissions.read, true); + assert.equal(permissions.edit, true); + assert.equal(permissions.delete, true); + }); }, mock() { return [ @@ -2021,12 +2065,12 @@ describe('Formio.js Tests', () => { components: [ { defaultPermission: 'admin', - key: 'groupField' - } - ] + key: 'groupField', + }, + ], }, }; - } + }, }, { url: `${Formio.getBaseUrl()}/access`, @@ -2035,13 +2079,13 @@ describe('Formio.js Tests', () => { return { status: 200, body: { - roles: [] - } + roles: [], + }, }; - } + }, }, ]; - } + }, }, { name: 'userPermissions method should handle submission with multiple groups', @@ -2056,30 +2100,28 @@ describe('Formio.js Tests', () => { data: { groupField: [ { - _id: 'test_group_id1' + _id: 'test_group_id1', }, { - _id: 'test_group_id2' - } - ] - } + _id: 'test_group_id2', + }, + ], + }, }; const formio = new Formio(`${Formio.getBaseUrl()}/testform`); return Promise.all([ - formio.userPermissions(user1, undefined, submission) - .then(permissions => { - assert.equal(permissions.create, false); - assert.equal(permissions.read, true); - assert.equal(permissions.edit, false); - assert.equal(permissions.delete, false); - }), - formio.userPermissions(user2, undefined, submission) - .then(permissions => { - assert.equal(permissions.create, false); - assert.equal(permissions.read, true); - assert.equal(permissions.edit, false); - assert.equal(permissions.delete, false); - }), + formio.userPermissions(user1, undefined, submission).then((permissions) => { + assert.equal(permissions.create, false); + assert.equal(permissions.read, true); + assert.equal(permissions.edit, false); + assert.equal(permissions.delete, false); + }), + formio.userPermissions(user2, undefined, submission).then((permissions) => { + assert.equal(permissions.create, false); + assert.equal(permissions.read, true); + assert.equal(permissions.edit, false); + assert.equal(permissions.delete, false); + }), ]); }, mock() { @@ -2095,12 +2137,12 @@ describe('Formio.js Tests', () => { components: [ { defaultPermission: 'read', - key: 'groupField' - } - ] + key: 'groupField', + }, + ], }, }; - } + }, }, { url: `${Formio.getBaseUrl()}/access`, @@ -2109,22 +2151,23 @@ describe('Formio.js Tests', () => { return { status: 200, body: { - roles: [] - } + roles: [], + }, }; - } + }, }, ]; - } + }, }, ]; tests.forEach(testCapability); }); - describe('Formio.currentUser', () => { + describe('Formio.currentUser', function () { let plugin: any = null; - beforeEach(() => { + + beforeEach(function () { plugin = { wrapStaticRequestPromise: sinon.spy((promise) => promise), staticRequest: sinon.spy(() => { @@ -2136,95 +2179,102 @@ describe('Formio.js Tests', () => { modified: new Date().toISOString(), data: { email: 'user@place.com', - name: 'user' + name: 'user', }, externalIds: [], externalTokens: [], form: generateID(), - owner: userId + owner: userId, }); - }) + }), }; Formio.registerPlugin(plugin, 'currentUserTestPlugin'); }); - afterEach(() => { + afterEach(function () { Formio.deregisterPlugin(plugin); }); - it('Initial currentUser() should make static request', (done) => { + it('Initial currentUser() should make static request', function (done) { // Force token Formio.token = chance.string({ length: 30 }); - Formio.currentUser() - .then(() => { - assert.ok(plugin.staticRequest.calledOnce, 'staticRequest should be called once'); - done(); - }); - assert.ok(plugin.wrapStaticRequestPromise.calledOnce, 'wrapStaticRequestPromise should be called once'); + Formio.currentUser().then(() => { + assert.ok(plugin.staticRequest.calledOnce, 'staticRequest should be called once'); + done(); + }); + assert.ok( + plugin.wrapStaticRequestPromise.calledOnce, + 'wrapStaticRequestPromise should be called once', + ); }); - it('Next currentUser() should return cached value', (done) => { + it('Next currentUser() should return cached value', function (done) { // Clear token - Formio.currentUser() - .then(() => { - assert.ok(!plugin.staticRequest.called, 'staticRequest should not be called'); - done(); - }); - assert.ok(plugin.wrapStaticRequestPromise.calledOnce, 'wrapStaticRequestPromise should be called once'); + Formio.currentUser().then(() => { + assert.ok(!plugin.staticRequest.called, 'staticRequest should not be called'); + done(); + }); + assert.ok( + plugin.wrapStaticRequestPromise.calledOnce, + 'wrapStaticRequestPromise should be called once', + ); }); }); - describe('Formio.request', () => { - it('should emit a formio.sessionExpired event when the response status is 440 and the response object should exist', (done) => { - let eventFired = false - let responseNotUndefined = false - setTimeout(()=>{ + + describe('Formio.request', function () { + it('should emit a formio.sessionExpired event when the response status is 440 and the response object should exist', function (done) { + let eventFired = false; + let responseNotUndefined = false; + setTimeout(() => { assert(eventFired, 'formio.sessionExpired event was not called'); assert(responseNotUndefined, 'a response was not passed into the event'); - fetchMock.restore() - done() - },200) + fetchMock.restore(); + done(); + }, 200); Formio.events.on('formio.sessionExpired', (response: any) => { - eventFired = true - if (response){ - responseNotUndefined = true + eventFired = true; + if (response) { + responseNotUndefined = true; } - }) + }); fetchMock.mock('http://localhost:8080/test', 440); Formio.request('http://localhost:8080/test'); }); - it('should emit a formio.unauthorized event when the response status is 401', (done) => { - let eventFired = false - let responseNotUndefined = false - setTimeout(()=>{ + + it('should emit a formio.unauthorized event when the response status is 401', function (done) { + let eventFired = false; + let responseNotUndefined = false; + setTimeout(() => { assert(eventFired, 'formio.unauthorized event was not called'); assert(responseNotUndefined, 'a response was not passed into the event'); - fetchMock.restore() - done() - },200); + fetchMock.restore(); + done(); + }, 200); Formio.events.on('formio.unauthorized', (response: any) => { eventFired = true; - if (response){ + if (response) { responseNotUndefined = true; } - }) + }); fetchMock.mock('http://localhost:8080/test', 401); Formio.request('http://localhost:8080/test'); }); - it('should emit a formio.rangeIsNotSatisfiable event when the response status is 416', (done) => { + + it('should emit a formio.rangeIsNotSatisfiable event when the response status is 416', function (done) { let eventFired = false; let responseNotUndefined = false; - setTimeout(()=>{ + setTimeout(() => { assert(eventFired, 'formio.rangeIsNotSatisfiable event was not called'); assert(responseNotUndefined, 'a response was not passed into the event'); - fetchMock.restore() - done() - },200); + fetchMock.restore(); + done(); + }, 200); Formio.events.on('formio.rangeIsNotSatisfiable', (response) => { eventFired = true; if (response) { responseNotUndefined = true; } - }) + }); fetchMock.mock('http://localhost:8080/test', 416); Formio.request('http://localhost:8080/test'); }); diff --git a/src/sdk/index.ts b/src/sdk/index.ts index b0aa474c..ef7a32c7 100644 --- a/src/sdk/index.ts +++ b/src/sdk/index.ts @@ -1 +1 @@ -export { Formio } from './Formio'; \ No newline at end of file +export { Formio } from './Formio'; diff --git a/src/server/actions/index.ts b/src/server/actions/index.ts index 7e163b7a..4c8db6c8 100644 --- a/src/server/actions/index.ts +++ b/src/server/actions/index.ts @@ -1,5 +1,5 @@ module.exports = { - save: require('./save/save'), - login: require('./login/login'), - role: require('./role/role') -}; \ No newline at end of file + save: require('./save/save'), + login: require('./login/login'), + role: require('./role/role'), +}; diff --git a/src/server/actions/login/login.js b/src/server/actions/login/login.js index 694a72a1..54b633bf 100644 --- a/src/server/actions/login/login.js +++ b/src/server/actions/login/login.js @@ -3,292 +3,288 @@ import { has, set, get, unset } from 'lodash'; const debug = require('debug')('formio:action:login'); const error = require('debug')('formio:error'); const LoginAction = { - // The action information. - get info() { - return { - name: 'login', - title: 'Login', - description: 'Provides a way to login to the application.', - priority: 2, - defaults: { - handler: ['before'], - method: ['create'], - }, - access: { - handler: false, - method: false, - }, - }; - }, + // The action information. + get info() { + return { + name: 'login', + title: 'Login', + description: 'Provides a way to login to the application.', + priority: 2, + defaults: { + handler: ['before'], + method: ['create'], + }, + access: { + handler: false, + method: false, + }, + }; + }, - /** - * The settings form for this action. - * @param {*} scope - */ - async settingsForm(scope) { - const fields = []; - const resources = []; - for (let name in scope.template.resources) { - const resource = scope.template.resources[name]; - resources.push({ - label: resource.title, - value: resource.name - }); - } - scope.utils.eachComponent(scope.form.components, (component) => { - if (['button'].indexOf(component.type) !== -1) { - return; - } - fields.push({ - label: component.label || component.key, - value: component.key - }); - }); - return [ - { - type: 'select', - label: 'Resources', - key: 'resources', - placeholder: 'Select the resources we should login against.', - dataSrc: 'json', - valueProperty: 'value', - data: { json: resources }, - multiple: true, - validate: { - required: true, - }, - }, - { - type: 'select', - input: true, - label: 'Username Field', - key: 'username', - placeholder: 'Select the username field', - dataSrc: 'json', - valueProperty: 'value', - data: { json: fields }, - multiple: false, - validate: { - required: true, - }, - }, - { - type: 'select', - label: 'Password Field', - key: 'password', - placeholder: 'Select the password field', - dataSrc: 'json', - valueProperty: 'value', - data: { json: fields }, - multiple: false, - validate: { - required: true, - }, - }, - { - type: 'textfield', - key: 'allowedAttempts', - input: true, - label: 'Maximum Login Attempts', - description: 'Use 0 for unlimited attempts', - defaultValue: '5', - }, - { - type: 'textfield', - key: 'attemptWindow', - input: true, - label: 'Login Attempt Time Window', - description: 'This is the window of time to count the login attempts.', - defaultValue: '30', - suffix: 'seconds', - }, - { - type: 'textfield', - key: 'lockWait', - input: true, - label: 'Locked Account Wait Time', - description: 'The amount of time a person needs to wait before they can try to login again.', - defaultValue: '1800', - suffix: 'seconds', - }, - ]; - }, + /** + * The settings form for this action. + * @param {*} scope + */ + async settingsForm(scope) { + const fields = []; + const resources = []; + for (let name in scope.template.resources) { + const resource = scope.template.resources[name]; + resources.push({ + label: resource.title, + value: resource.name, + }); + } + scope.utils.eachComponent(scope.form.components, (component) => { + if (['button'].indexOf(component.type) !== -1) { + return; + } + fields.push({ + label: component.label || component.key, + value: component.key, + }); + }); + return [ + { + type: 'select', + label: 'Resources', + key: 'resources', + placeholder: 'Select the resources we should login against.', + dataSrc: 'json', + valueProperty: 'value', + data: { json: resources }, + multiple: true, + validate: { + required: true, + }, + }, + { + type: 'select', + input: true, + label: 'Username Field', + key: 'username', + placeholder: 'Select the username field', + dataSrc: 'json', + valueProperty: 'value', + data: { json: fields }, + multiple: false, + validate: { + required: true, + }, + }, + { + type: 'select', + label: 'Password Field', + key: 'password', + placeholder: 'Select the password field', + dataSrc: 'json', + valueProperty: 'value', + data: { json: fields }, + multiple: false, + validate: { + required: true, + }, + }, + { + type: 'textfield', + key: 'allowedAttempts', + input: true, + label: 'Maximum Login Attempts', + description: 'Use 0 for unlimited attempts', + defaultValue: '5', + }, + { + type: 'textfield', + key: 'attemptWindow', + input: true, + label: 'Login Attempt Time Window', + description: 'This is the window of time to count the login attempts.', + defaultValue: '30', + suffix: 'seconds', + }, + { + type: 'textfield', + key: 'lockWait', + input: true, + label: 'Locked Account Wait Time', + description: + 'The amount of time a person needs to wait before they can try to login again.', + defaultValue: '1800', + suffix: 'seconds', + }, + ]; + }, - /** - * Format a string to show how long one must wait. - * - * @param time - In seconds. - * @returns {string} - */ - waitText(time) { - return (time > 60) ? `${parseInt(time / 60, 10)} minutes` : `${parseInt(time, 10)} seconds`; - }, + /** + * Format a string to show how long one must wait. + * + * @param time - In seconds. + * @returns {string} + */ + waitText(time) { + return time > 60 ? `${parseInt(time / 60, 10)} minutes` : `${parseInt(time, 10)} seconds`; + }, - /** - * Checks the login attempts for a certain login. - * - * @param user - * @param next - * @returns {*} - */ - async checkAttempts(scope, error, user) { - const action = scope.action; - if (!user || !user._id || !action.settings.allowedAttempts) { - return; - } + /** + * Checks the login attempts for a certain login. + * + * @param user + * @param next + * @returns {*} + */ + async checkAttempts(scope, error, user) { + const action = scope.action; + if (!user || !user._id || !action.settings.allowedAttempts) { + return; + } - const allowedAttempts = parseInt(action.settings.allowedAttempts, 10); - if (Number.isNaN(allowedAttempts) || allowedAttempts === 0) { - return; - } + const allowedAttempts = parseInt(action.settings.allowedAttempts, 10); + if (Number.isNaN(allowedAttempts) || allowedAttempts === 0) { + return; + } - // Initialize the login metadata. - if (!has(user, 'metadata.login')) { - set(user, 'metadata.login', {}); - } + // Initialize the login metadata. + if (!has(user, 'metadata.login')) { + set(user, 'metadata.login', {}); + } - const now = (new Date()).getTime(); - const { - login: loginMetadata, - } = user.metadata; - const lastAttempt = parseInt(loginMetadata.last, 10) || 0; + const now = new Date().getTime(); + const { login: loginMetadata } = user.metadata; + const lastAttempt = parseInt(loginMetadata.last, 10) || 0; - // See if the login is locked. - if (loginMetadata.locked) { - // Get how long they must wait to be locked out. - let lockWait = parseInt(action.settings.lockWait, 10) || 1800; + // See if the login is locked. + if (loginMetadata.locked) { + // Get how long they must wait to be locked out. + let lockWait = parseInt(action.settings.lockWait, 10) || 1800; - // Normalize to milliseconds. - lockWait *= 1000; + // Normalize to milliseconds. + lockWait *= 1000; - // See if the time has expired. - if ((lastAttempt + lockWait) < now) { - // Reset the locked state and attempts totals. - loginMetadata.attempts = 0; - loginMetadata.locked = false; - loginMetadata.last = now; - } - else { - const howLong = (lastAttempt + lockWait) - now; - return `You must wait ${LoginAction.waitText(howLong / 1000)} before you can login.`; - } - } - else if (error) { - let attemptWindow = parseInt(action.settings.attemptWindow, 10) || 30; + // See if the time has expired. + if (lastAttempt + lockWait < now) { + // Reset the locked state and attempts totals. + loginMetadata.attempts = 0; + loginMetadata.locked = false; + loginMetadata.last = now; + } else { + const howLong = lastAttempt + lockWait - now; + return `You must wait ${LoginAction.waitText(howLong / 1000)} before you can login.`; + } + } else if (error) { + let attemptWindow = parseInt(action.settings.attemptWindow, 10) || 30; - // Normalize to milliseconds. - attemptWindow *= 1000; + // Normalize to milliseconds. + attemptWindow *= 1000; - // Determine the login attempts within a certain window. - const withinWindow = lastAttempt ? ((lastAttempt + attemptWindow) > now) : false; + // Determine the login attempts within a certain window. + const withinWindow = lastAttempt ? lastAttempt + attemptWindow > now : false; - if (withinWindow) { - const attempts = (parseInt(loginMetadata.attempts, 10) || 0) + 1; + if (withinWindow) { + const attempts = (parseInt(loginMetadata.attempts, 10) || 0) + 1; - // If they exceeded the login attempts. - if (attempts >= allowedAttempts) { - const lockWait = parseInt(action.settings.lockWait, 10) || 1800; - error = `Maximum Login attempts. Please wait ${LoginAction.waitText(lockWait)} before trying again.`; - loginMetadata.locked = true; - } - - // Set the login attempts. - loginMetadata.attempts = attempts; - } - else { - loginMetadata.attempts = 0; - loginMetadata.last = now; - } - } - else { - // If there was no error, then reset the attempts to zero. - loginMetadata.attempts = 0; - loginMetadata.last = now; + // If they exceeded the login attempts. + if (attempts >= allowedAttempts) { + const lockWait = parseInt(action.settings.lockWait, 10) || 1800; + error = `Maximum Login attempts. Please wait ${LoginAction.waitText(lockWait)} before trying again.`; + loginMetadata.locked = true; } - // Update the user record - await scope.db.update(scope, user._id.toString(), user); - return error; - }, + // Set the login attempts. + loginMetadata.attempts = attempts; + } else { + loginMetadata.attempts = 0; + loginMetadata.last = now; + } + } else { + // If there was no error, then reset the attempts to zero. + loginMetadata.attempts = 0; + loginMetadata.last = now; + } + + // Update the user record + await scope.db.update(scope, user._id.toString(), user); + return error; + }, - /** - * Returns the action middleware. - * - * @param {*} scope - */ - async executor(scope) { - const action = scope.action; - const userfield = action.settings.username; - const passfield = action.settings.password; - const forms = await scope.utils.getForms(scope, action.settings.resources); - return async (req, res, next) => { - debug('Login Action'); - const username = get(req.body?.data, userfield); - const password = get(req.body?.data, passfield); - if (!username) { - error('Missing username'); - return next('Missing username'); - } - if (!password) { - error('Missing password'); - return next('Missing password'); - } + /** + * Returns the action middleware. + * + * @param {*} scope + */ + async executor(scope) { + const action = scope.action; + const userfield = action.settings.username; + const passfield = action.settings.password; + const forms = await scope.utils.getForms(scope, action.settings.resources); + return async (req, res, next) => { + debug('Login Action'); + const username = get(req.body?.data, userfield); + const password = get(req.body?.data, passfield); + if (!username) { + error('Missing username'); + return next('Missing username'); + } + if (!password) { + error('Missing password'); + return next('Missing password'); + } - // Find the user - debug('Finding user', `${userfield} = ${username}`); - const user = await scope.utils.findUser(scope, forms, `data.${userfield}`, username); - if (!user) { - error('User not found'); - return next('User or password was incorrect'); - } + // Find the user + debug('Finding user', `${userfield} = ${username}`); + const user = await scope.utils.findUser(scope, forms, `data.${userfield}`, username); + if (!user) { + error('User not found'); + return next('User or password was incorrect'); + } - // Get the current password hash. - const hash = get(user.data, passfield); - if (!hash || !hash.hash) { - error('User does not have a password'); - return next('Your account does not have a password. You must reset your password to login.'); - } + // Get the current password hash. + const hash = get(user.data, passfield); + if (!hash || !hash.hash) { + error('User does not have a password'); + return next( + 'Your account does not have a password. You must reset your password to login.', + ); + } - // Compare with bcrypt. - debug('Comparing password'); - bcrypt.compare(password, hash.hash, async (err, value) => { - if (err) { - error(err); - return next(err); - } + // Compare with bcrypt. + debug('Comparing password'); + bcrypt.compare(password, hash.hash, async (err, value) => { + if (err) { + error(err); + return next(err); + } - // Check the login attempts. - const error = await LoginAction.checkAttempts(scope, !value, user); - if (error) { - error(error); - return next(error === true ? 'User or password was incorrect' : error); - } + // Check the login attempts. + const error = await LoginAction.checkAttempts(scope, !value, user); + if (error) { + error(error); + return next(error === true ? 'User or password was incorrect' : error); + } - // Unset the password field before we create a token from it. - unset(user.data, passfield); + // Unset the password field before we create a token from it. + unset(user.data, passfield); - // Set the user object. - req.user = user; - req.token = await scope.auth.token( - scope.utils.tokenFromUser(user), - scope.config.auth.secret, - scope.config.auth.expire - ); + // Set the user object. + req.user = user; + req.token = await scope.auth.token( + scope.utils.tokenFromUser(user), + scope.config.auth.secret, + scope.config.auth.expire, + ); - // Set the auth headers. - res.setHeader('x-jwt-token', req.token); - req.headers['x-jwt-token'] = req.token; - if (res.resource) { - res.resource.item = req.user; - } - else { - res.resource = { status: 200, item: req.user }; - } - debug('Login Successful', req.user); - next(); - }); - }; - } + // Set the auth headers. + res.setHeader('x-jwt-token', req.token); + req.headers['x-jwt-token'] = req.token; + if (res.resource) { + res.resource.item = req.user; + } else { + res.resource = { status: 200, item: req.user }; + } + debug('Login Successful', req.user); + next(); + }); + }; + }, }; -module.exports = LoginAction; \ No newline at end of file +module.exports = LoginAction; diff --git a/src/server/actions/role/role.js b/src/server/actions/role/role.js index 3b427d25..e83bd340 100644 --- a/src/server/actions/role/role.js +++ b/src/server/actions/role/role.js @@ -1,164 +1,193 @@ const debug = require('debug')('formio:actions:role'); const error = require('debug')('formio:error'); const RoleAction = { - // The action information. - get info() { - return { - name: 'role', - title: 'Role Assignment', - description: 'Provides the Role Assignment capabilities.', - priority: 1, - defaults: { - handler: ['after'], - method: ['create'] - }, - access: { - handler: false, - method: false - } - }; - }, + // The action information. + get info() { + return { + name: 'role', + title: 'Role Assignment', + description: 'Provides the Role Assignment capabilities.', + priority: 1, + defaults: { + handler: ['after'], + method: ['create'], + }, + access: { + handler: false, + method: false, + }, + }; + }, - /** - * The settings form for this action. - * @param {*} scope - */ - async settingsForm(scope) { - return [ + /** + * The settings form for this action. + * @param {*} scope + */ + async settingsForm(scope) { + return [ + { + type: 'select', + input: true, + label: 'Resource Association', + key: 'association', + placeholder: 'Select the type of resource to perform role manipulation.', + template: '{{ item.title }}', + dataSrc: 'json', + data: { + json: JSON.stringify([ + { + association: 'existing', + title: 'Existing Resource', + }, { - type: 'select', - input: true, - label: 'Resource Association', - key: 'association', - placeholder: 'Select the type of resource to perform role manipulation.', - template: '{{ item.title }}', - dataSrc: 'json', - data: { - json: JSON.stringify([ - { - association: 'existing', - title: 'Existing Resource' - }, - { - association: 'new', - title: 'New Resource' - } - ]) - }, - valueProperty: 'association', - multiple: false, - validate: { - required: true - } + association: 'new', + title: 'New Resource', }, + ]), + }, + valueProperty: 'association', + multiple: false, + validate: { + required: true, + }, + }, + { + type: 'select', + input: true, + label: 'Action Type', + key: 'type', + placeholder: 'Select whether this Action will Add or Remove the contained Role.', + template: '{{ item.title }}', + dataSrc: 'json', + data: { + json: JSON.stringify([ { - type: 'select', - input: true, - label: 'Action Type', - key: 'type', - placeholder: 'Select whether this Action will Add or Remove the contained Role.', - template: '{{ item.title }}', - dataSrc: 'json', - data: { - json: JSON.stringify([ - { - type: 'add', - title: 'Add Role' - }, - { - type: 'remove', - title: 'Remove Role' - } - ]) - }, - valueProperty: 'type', - multiple: false, - validate: { - required: true - } + type: 'add', + title: 'Add Role', }, { - type: 'select', - input: true, - label: 'Role', - key: 'role', - placeholder: 'Select the Role that this action will Add or Remove.', - template: '{{ item.title }}', - dataSrc: 'json', - data: { json: Object.values(scope.template.roles) }, - valueProperty: '_id', - multiple: false, - validate: { - required: true - } - } - ] - }, + type: 'remove', + title: 'Remove Role', + }, + ]), + }, + valueProperty: 'type', + multiple: false, + validate: { + required: true, + }, + }, + { + type: 'select', + input: true, + label: 'Role', + key: 'role', + placeholder: 'Select the Role that this action will Add or Remove.', + template: '{{ item.title }}', + dataSrc: 'json', + data: { json: Object.values(scope.template.roles) }, + valueProperty: '_id', + multiple: false, + validate: { + required: true, + }, + }, + ]; + }, - /** - * Returns the action middleware. - * - * @param {*} scope - */ - async executor(scope) { - return async (req, res, next) => { - debug('Role Action'); - // Check the submission for the submissionId. - if (scope.action.settings.association !== 'existing' && scope.action.settings.association !== 'new') { - error('Invalid setting `association` for the RoleAction; expecting `new` or `existing`.'); - return res.status(400).send('Invalid setting `association` for the RoleAction; expecting `new` or `existing`.'); - } - // Error if operation type is not valid. - if (!scope.action.settings.type || (scope.action.settings.type !== 'add' && scope.action.settings.type !== 'remove')) { - error('Invalid setting `type` for the RoleAction; expecting `add` or `remove`.'); - return res.status(400).send('Invalid setting `type` for the RoleAction; expecting `add` or `remove`.'); - } - // Error if no resource is being returned. - if (scope.action.settings.association === 'new' && res.hasOwnProperty('resource') && !res.resource.item && scope.action.settings.role) { - error('Invalid resource was provided for RoleAction association of `new`.'); - return res.status(400).send('Invalid resource was provided for RoleAction association of `new`.'); - } - // Error if association is existing and valid data was not provided. - if (scope.action.settings.association === 'existing' && !scope.action.settings.role) { - error('Missing role for RoleAction association of "existing". Must specify role to assign in action settings or a form component named "role"'); - return res.status(400).send('Missing role for RoleAction association of "existing". Must specify role to assign in action settings or a form component named "role"'); - } - if (scope.action.settings.association === 'existing' && !res.resource.item) { - error('Missing submission for RoleAction association of "existing:. Form must have a resource field named "submission".'); - return res.status(400).send('Missing submission for RoleAction association of "existing:. Form must have a resource field named "submission".'); - } + /** + * Returns the action middleware. + * + * @param {*} scope + */ + async executor(scope) { + return async (req, res, next) => { + debug('Role Action'); + // Check the submission for the submissionId. + if ( + scope.action.settings.association !== 'existing' && + scope.action.settings.association !== 'new' + ) { + error('Invalid setting `association` for the RoleAction; expecting `new` or `existing`.'); + return res + .status(400) + .send('Invalid setting `association` for the RoleAction; expecting `new` or `existing`.'); + } + // Error if operation type is not valid. + if ( + !scope.action.settings.type || + (scope.action.settings.type !== 'add' && scope.action.settings.type !== 'remove') + ) { + error('Invalid setting `type` for the RoleAction; expecting `add` or `remove`.'); + return res + .status(400) + .send('Invalid setting `type` for the RoleAction; expecting `add` or `remove`.'); + } + // Error if no resource is being returned. + if ( + scope.action.settings.association === 'new' && + res.hasOwnProperty('resource') && + !res.resource.item && + scope.action.settings.role + ) { + error('Invalid resource was provided for RoleAction association of `new`.'); + return res + .status(400) + .send('Invalid resource was provided for RoleAction association of `new`.'); + } + // Error if association is existing and valid data was not provided. + if (scope.action.settings.association === 'existing' && !scope.action.settings.role) { + error( + 'Missing role for RoleAction association of "existing". Must specify role to assign in action settings or a form component named "role"', + ); + return res + .status(400) + .send( + 'Missing role for RoleAction association of "existing". Must specify role to assign in action settings or a form component named "role"', + ); + } + if (scope.action.settings.association === 'existing' && !res.resource.item) { + error( + 'Missing submission for RoleAction association of "existing:. Form must have a resource field named "submission".', + ); + return res + .status(400) + .send( + 'Missing submission for RoleAction association of "existing:. Form must have a resource field named "submission".', + ); + } - // Determine the resources based on the current request. - let resource = res.resource ? (res.resource.item || req.body) : req.body; - let role = scope.utils.roleId(scope, scope.action.settings.role); + // Determine the resources based on the current request. + let resource = res.resource ? res.resource.item || req.body : req.body; + let role = scope.utils.roleId(scope, scope.action.settings.role); - if (!resource.roles) { - resource.roles = []; - } + if (!resource.roles) { + resource.roles = []; + } - const roleIndex = resource.roles.indexOf(role); - switch (scope.action.settings.type) { - case 'add': - if (roleIndex !== -1) { - return next(); - } - resource.roles.push(role); - break; - case 'remove': - if (roleIndex === -1) { - return next(); - } - resource.roles.slice(roleIndex, 1); - break; - } + const roleIndex = resource.roles.indexOf(role); + switch (scope.action.settings.type) { + case 'add': + if (roleIndex !== -1) { + return next(); + } + resource.roles.push(role); + break; + case 'remove': + if (roleIndex === -1) { + return next(); + } + resource.roles.slice(roleIndex, 1); + break; + } - debug('Updating user with roles', resource.roles); + debug('Updating user with roles', resource.roles); - // Update the user. - await scope.db.update(scope, resource._id, resource, ['roles']); - next(); - }; - } + // Update the user. + await scope.db.update(scope, resource._id, resource, ['roles']); + next(); + }; + }, }; module.exports = RoleAction; diff --git a/src/server/actions/save/save.js b/src/server/actions/save/save.js index 30b2e9ca..d51669be 100644 --- a/src/server/actions/save/save.js +++ b/src/server/actions/save/save.js @@ -3,304 +3,310 @@ const async = require('async'); const debug = require('debug')('formio:actions:save'); const error = require('debug')('formio:error'); const SaveAction = { - // The action information. - get info() { - return { - name: 'save', - title: 'Save Submission', - description: 'Saves the submission into the database.', - priority: 10, - defaults: { - handler: ['before'], - method: ['create', 'update'] - }, - access: { - handler: false, - method: false - } - }; - }, + // The action information. + get info() { + return { + name: 'save', + title: 'Save Submission', + description: 'Saves the submission into the database.', + priority: 10, + defaults: { + handler: ['before'], + method: ['create', 'update'], + }, + access: { + handler: false, + method: false, + }, + }; + }, - async mappingComponents(scope) { - const components = [ - { - type: 'select', - key: 'mapType', - label: 'Request Mapping Type', - persist: 'client-only', - defaultValue: 'simple', - dataSrc: 'values', - data: { - values: [ - { label: 'Simple', value: 'simple' }, - { label: 'Advanced', value: 'advanced' } - ] - } - }, - { - type: 'panel', - title: 'Advanced Request Mapping', - key: 'requestMappingPanel', - customConditional: `show = row.mapType === 'advanced'`, - components: [ - { - input: true, - label: "Request Mapping", - key: "mapping", - placeholder: "/** Example Code **/\nbody = submission;", - rows: 8, - defaultValue: "", - persistent: true, - editor: "ace", - type: "textarea", - description: "Manually perform a mapping of the request being made to the child resource. The 'body' is the req.body sent to the resource. You can use any standard evaluation context variables (form, submission, etc)." - } - ] - } - ]; - for (let key in scope.template.resources) { - const form = scope.template.resources[key]; - const mappings = { - title: 'Simple Mappings', - label: 'Simple Mappings', - collapsible: false, - key: 'mappings', - type: 'panel', - customConditional: `show = row.mapType === 'simple' && row.resource === "${key}"`, - components: [] - }; - const toFields = []; - await scope.utils.eachComponent(form.components, (component) => { - if (['button'].indexOf(component.type) !== -1) { - return; - } - toFields.push({ label: component.label || component.key, value: component.key }); - }); - await scope.utils.eachComponent(scope.form.components, (component) => { - if (['button'].indexOf(component.type) !== -1) { - return; - } - mappings.components.push({ - type: 'select', - key: `fields.${component.key}`, - label: component.label, - valueProperty: 'value', - dataSrc: 'json', - data: { json: toFields } - }); - }); - components.push(mappings); + async mappingComponents(scope) { + const components = [ + { + type: 'select', + key: 'mapType', + label: 'Request Mapping Type', + persist: 'client-only', + defaultValue: 'simple', + dataSrc: 'values', + data: { + values: [ + { label: 'Simple', value: 'simple' }, + { label: 'Advanced', value: 'advanced' }, + ], + }, + }, + { + type: 'panel', + title: 'Advanced Request Mapping', + key: 'requestMappingPanel', + customConditional: `show = row.mapType === 'advanced'`, + components: [ + { + input: true, + label: 'Request Mapping', + key: 'mapping', + placeholder: '/** Example Code **/\nbody = submission;', + rows: 8, + defaultValue: '', + persistent: true, + editor: 'ace', + type: 'textarea', + description: + "Manually perform a mapping of the request being made to the child resource. The 'body' is the req.body sent to the resource. You can use any standard evaluation context variables (form, submission, etc).", + }, + ], + }, + ]; + for (let key in scope.template.resources) { + const form = scope.template.resources[key]; + const mappings = { + title: 'Simple Mappings', + label: 'Simple Mappings', + collapsible: false, + key: 'mappings', + type: 'panel', + customConditional: `show = row.mapType === 'simple' && row.resource === "${key}"`, + components: [], + }; + const toFields = []; + await scope.utils.eachComponent(form.components, (component) => { + if (['button'].indexOf(component.type) !== -1) { + return; } - return components; - }, - - /** - * The settings form for this action. - * @param {*} scope - */ - async settingsForm(scope) { - const resources = []; - for (let name in scope.template.resources) { - resources.push({ - label: scope.template.resources[name].title, - value: name - }) + toFields.push({ label: component.label || component.key, value: component.key }); + }); + await scope.utils.eachComponent(scope.form.components, (component) => { + if (['button'].indexOf(component.type) !== -1) { + return; } - return [ - { - type: 'select', - key: 'resource', - label: 'Save submission to', - placeholder: 'This form', - valueProperty: 'value', - dataSrc: 'json', - data: { - json: resources - }, - required: false - }, - { - type: 'textfield', - key: 'property', - label: 'Resource Property', - placeholder: 'Assign this resource to the following property', - customConditional: 'show = row.resource' - }, - { - legend: 'Resource Fields', - key: 'resourceFields', - type: 'fieldset', - label: 'Resource Fields', - customConditional: 'show = row.resource', - components: [ - { - label: 'Summary', - key: 'summary', - type: 'well', - hideLabel: true, - components: [ - { - label: 'HTML', - content: 'Below are the fields within the selected resource. For each of these fields, select the corresponding field within this form that you wish to map to the selected Resource. Simple mappings may be used for any component that is not nested within a container, editgrid, datagrid or other nested data component.', - refreshOnChange: false, - attrs: [{ attr: 'style', value: 'margin: 0' }], - key: 'html', - type: 'htmlelement' - } - ] - } - ].concat(await SaveAction.mappingComponents(scope)) - }, - { - type: 'panel', - title: 'Transform Mappings', - key: 'transformPanel', - components: [ - { - input: true, - label: "Transform Data", - key: "transform", - placeholder: "/** Example Code **/\ndata = submission.data;", - rows: 8, - defaultValue: "", - persistent: true, - editor: "ace", - type: "textarea", - description: "Available variables are submission and data (data is already transformed by simple mappings)." - } - ] - } - ]; - }, - - saveToForm(scope, resource) { - let saveTo; - each(scope.template.resources, (form) => { - if (form.key === resource) { - saveTo = form; - return false; - } + mappings.components.push({ + type: 'select', + key: `fields.${component.key}`, + label: component.label, + valueProperty: 'value', + dataSrc: 'json', + data: { json: toFields }, }); - if (!saveTo) { - each(scope.template.forms, (form) => { - if (form.key === resource) { - saveTo = form; - return false; - } - }); - } - return saveTo; - }, + }); + components.push(mappings); + } + return components; + }, - // Create a child submission. - childSubmission(scope, req, res, submission) { - const { action } = scope; - let childSub = { data: {} }; - if (action.settings.mapping) { - try { - childSub = scope.utils.evaluate( - action.settings.mapping, - scope.utils.evalContext({ - ...scope, - body: req.body - }, req, res), - 'body' - ); - } - catch (err) { - console.log(`Error in mapping transform: ${err.message}`); - } - } - else { - each(action.settings.fields, function (field, key) { - if (field === 'data') { - set(childSub.data, key, submission.data); - } - else if (has(submission.data, field)) { - set(childSub.data, key, get(submission.data, field)); - } - }); + /** + * The settings form for this action. + * @param {*} scope + */ + async settingsForm(scope) { + const resources = []; + for (let name in scope.template.resources) { + resources.push({ + label: scope.template.resources[name].title, + value: name, + }); + } + return [ + { + type: 'select', + key: 'resource', + label: 'Save submission to', + placeholder: 'This form', + valueProperty: 'value', + dataSrc: 'json', + data: { + json: resources, + }, + required: false, + }, + { + type: 'textfield', + key: 'property', + label: 'Resource Property', + placeholder: 'Assign this resource to the following property', + customConditional: 'show = row.resource', + }, + { + legend: 'Resource Fields', + key: 'resourceFields', + type: 'fieldset', + label: 'Resource Fields', + customConditional: 'show = row.resource', + components: [ + { + label: 'Summary', + key: 'summary', + type: 'well', + hideLabel: true, + components: [ + { + label: 'HTML', + content: + 'Below are the fields within the selected resource. For each of these fields, select the corresponding field within this form that you wish to map to the selected Resource. Simple mappings may be used for any component that is not nested within a container, editgrid, datagrid or other nested data component.', + refreshOnChange: false, + attrs: [{ attr: 'style', value: 'margin: 0' }], + key: 'html', + type: 'htmlelement', + }, + ], + }, + ].concat(await SaveAction.mappingComponents(scope)), + }, + { + type: 'panel', + title: 'Transform Mappings', + key: 'transformPanel', + components: [ + { + input: true, + label: 'Transform Data', + key: 'transform', + placeholder: '/** Example Code **/\ndata = submission.data;', + rows: 8, + defaultValue: '', + persistent: true, + editor: 'ace', + type: 'textarea', + description: + 'Available variables are submission and data (data is already transformed by simple mappings).', + }, + ], + }, + ]; + }, + + saveToForm(scope, resource) { + let saveTo; + each(scope.template.resources, (form) => { + if (form.key === resource) { + saveTo = form; + return false; + } + }); + if (!saveTo) { + each(scope.template.forms, (form) => { + if (form.key === resource) { + saveTo = form; + return false; } + }); + } + return saveTo; + }, - childSub.metadata = submission.metadata; - if (action.settings.transform) { - try { - childSub.data = scope.utils.evaluate( - action.settings.transform, - scope.utils.evalContext(scope, req, res), - 'data' - ); - } - catch (err) { - console.log(`Error in submission transform: ${err.message}`); - } + // Create a child submission. + childSubmission(scope, req, res, submission) { + const { action } = scope; + let childSub = { data: {} }; + if (action.settings.mapping) { + try { + childSub = scope.utils.evaluate( + action.settings.mapping, + scope.utils.evalContext( + { + ...scope, + body: req.body, + }, + req, + res, + ), + 'body', + ); + } catch (err) { + console.log(`Error in mapping transform: ${err.message}`); + } + } else { + each(action.settings.fields, function (field, key) { + if (field === 'data') { + set(childSub.data, key, submission.data); + } else if (has(submission.data, field)) { + set(childSub.data, key, get(submission.data, field)); } + }); + } - return childSub; - }, + childSub.metadata = submission.metadata; + if (action.settings.transform) { + try { + childSub.data = scope.utils.evaluate( + action.settings.transform, + scope.utils.evalContext(scope, req, res), + 'data', + ); + } catch (err) { + console.log(`Error in submission transform: ${err.message}`); + } + } - // Set the child response - childResponse(scope, req, res) { - const { action } = scope; - if (res.resource?.item) { - // Set the action in the property. - if (action.settings?.property) { - set(req.body.data, action.settings.property, res.resource.item); - } + return childSub; + }, - // Save the reference in the external ids. - if (req.method === 'POST' && res.resource.item._id) { - // Save the external resource in the external ids. - req.body.externalIds = req.body.externalIds || []; - req.body.externalIds.push({ - type: 'resource', - resource: action.settings.resource, - id: res.resource.item._id.toString() - }); - } - } - }, + // Set the child response + childResponse(scope, req, res) { + const { action } = scope; + if (res.resource?.item) { + // Set the action in the property. + if (action.settings?.property) { + set(req.body.data, action.settings.property, res.resource.item); + } - async executor(scope) { - const action = scope.action; - return async (req, res, next) => { - debug('Save Action'); - if (req.skipSave || !req.body || (req.method !== 'POST' && req.method !== 'PUT')) { - debug('Skipping save action'); - return next(); - } + // Save the reference in the external ids. + if (req.method === 'POST' && res.resource.item._id) { + // Save the external resource in the external ids. + req.body.externalIds = req.body.externalIds || []; + req.body.externalIds.push({ + type: 'resource', + resource: action.settings.resource, + id: res.resource.item._id.toString(), + }); + } + } + }, - // If this is saving to another resource, then we need to use those handlers instead. - if (action.settings?.resource) { - debug('Saving to resource: ' + action.settings.resource); - const saveTo = SaveAction.saveToForm(scope, action.settings.resource); - if (saveTo) { - if (!saveTo.handlers) { - error('Cannot find resource handlers.'); - return next('Cannot find resource handlers.'); - } - const handlers = req.method === 'PUT' ? saveTo.handlers.update : saveTo.handlers.create; - const childReq = scope.utils.childRequest(req); - childReq.body = SaveAction.childSubmission(scope, req, res, childReq.body); - return async.series(handlers.map(handler => async.apply(handler, childReq, res)), (err) => { - if (err) { - error(err); - return next(err); - } + async executor(scope) { + const action = scope.action; + return async (req, res, next) => { + debug('Save Action'); + if (req.skipSave || !req.body || (req.method !== 'POST' && req.method !== 'PUT')) { + debug('Skipping save action'); + return next(); + } - // Set the child response based on the response of the subform. - SaveAction.childResponse(scope, req, res); - next(); - }); - } - } + // If this is saving to another resource, then we need to use those handlers instead. + if (action.settings?.resource) { + debug('Saving to resource: ' + action.settings.resource); + const saveTo = SaveAction.saveToForm(scope, action.settings.resource); + if (saveTo) { + if (!saveTo.handlers) { + error('Cannot find resource handlers.'); + return next('Cannot find resource handlers.'); + } + const handlers = req.method === 'PUT' ? saveTo.handlers.update : saveTo.handlers.create; + const childReq = scope.utils.childRequest(req); + childReq.body = SaveAction.childSubmission(scope, req, res, childReq.body); + return async.series( + handlers.map((handler) => async.apply(handler, childReq, res)), + (err) => { + if (err) { + error(err); + return next(err); + } - // Save the submission. - req.scope.saveSubmission = true; - debug('Saving submission'); - return next(); - }; - } + // Set the child response based on the response of the subform. + SaveAction.childResponse(scope, req, res); + next(); + }, + ); + } + } + + // Save the submission. + req.scope.saveSubmission = true; + debug('Saving submission'); + return next(); + }; + }, }; -module.exports = SaveAction; \ No newline at end of file +module.exports = SaveAction; diff --git a/src/server/auth.js b/src/server/auth.js index c92543a6..710d4e1e 100644 --- a/src/server/auth.js +++ b/src/server/auth.js @@ -2,52 +2,57 @@ const jwt = require('jsonwebtoken'); const debug = require('debug')('formio:auth'); const error = require('debug')('formio:error'); class Auth { - async token(payload, secret, expire = 240) { - payload = Object.assign({}, payload); - delete payload.iat; - delete payload.exp; - return new Promise((resolve, reject) => { - if (!secret) { - return reject('You cannot generate a token without a secret!'); - } - debug('auth.token()', payload); - jwt.sign(payload, secret, { - expiresIn: expire * 60, - }, (err, signed) => { - if (err) { - error(err); - return reject(err); - } - resolve(signed); - }); - }); - } + async token(payload, secret, expire = 240) { + payload = Object.assign({}, payload); + delete payload.iat; + delete payload.exp; + return new Promise((resolve, reject) => { + if (!secret) { + return reject('You cannot generate a token without a secret!'); + } + debug('auth.token()', payload); + jwt.sign( + payload, + secret, + { + expiresIn: expire * 60, + }, + (err, signed) => { + if (err) { + error(err); + return reject(err); + } + resolve(signed); + }, + ); + }); + } - async user(token, secret) { - if (!token) { - return Promise.resolve(null); - } - return new Promise((resolve, reject) => { - if (!secret) { - return reject('You cannot authenticate without a JWT Secret!'); - } - debug('auth.verify()', token); - jwt.verify(token, secret, (err, payload) => { - if (err) { - error(err); - if (err.name === 'JsonWebTokenError') { - return reject({message: 'Bad Token'}); - } - if (err.name === 'TokenExpiredError') { - return reject({message: 'Token Expired'}); - } - return reject(err); - } - debug('auth.user()', payload); - resolve(payload); - }); - }); + async user(token, secret) { + if (!token) { + return Promise.resolve(null); } + return new Promise((resolve, reject) => { + if (!secret) { + return reject('You cannot authenticate without a JWT Secret!'); + } + debug('auth.verify()', token); + jwt.verify(token, secret, (err, payload) => { + if (err) { + error(err); + if (err.name === 'JsonWebTokenError') { + return reject({ message: 'Bad Token' }); + } + if (err.name === 'TokenExpiredError') { + return reject({ message: 'Token Expired' }); + } + return reject(err); + } + debug('auth.user()', payload); + resolve(payload); + }); + }); + } } -module.exports = Auth; \ No newline at end of file +module.exports = Auth; diff --git a/src/server/db.js b/src/server/db.js index 2eb271b7..a2f6e452 100644 --- a/src/server/db.js +++ b/src/server/db.js @@ -3,338 +3,328 @@ const debug = require('debug')('formio:db'); const error = require('debug')('formio:error'); import { pick, omit } from 'lodash'; class Database { - constructor(config) { - this.config = config; - this.db = null; - this.currentCollectionName = 'submissions'; - this.currentCollection = null; - this.defaultCollection = null; + constructor(config) { + this.config = config; + this.db = null; + this.currentCollectionName = 'submissions'; + this.currentCollection = null; + this.defaultCollection = null; + } + + ObjectId(id) { + if (id?.hasOwnProperty('$in')) { + return { $in: id['$in'].map((_id) => this.ObjectId(_id)) }; + } + try { + return id ? new ObjectId(id) : null; + } catch (e) { + return id; } + } - ObjectId(id) { - if (id?.hasOwnProperty('$in')) { - return {$in: id['$in'].map((_id) => this.ObjectId(_id))}; - } - try { - return id ? (new ObjectId(id)) : null; - } - catch (e) { - return id; - } + /** + * Connect to the database. + * @param {*} scope + * @returns + */ + async connect() { + try { + debug('db.connect()'); + const config = this.config.config ? JSON.parse(this.config.config) : {}; + const client = new MongoClient(this.config.url, config); + await client.connect(); + this.db = await client.db(); + this.addIndex(this.db.collection('project'), 'name'); + this.defaultCollection = this.db.collection('submissions'); + await this.setupIndexes(this.defaultCollection); + debug('Connected to database'); + } catch (err) { + error(err.message); + process.exit(); } + } - /** - * Connect to the database. - * @param {*} scope - * @returns - */ - async connect() { - try { - debug('db.connect()'); - const config = this.config.config ? JSON.parse(this.config.config) : {}; - const client = new MongoClient(this.config.url, config); - await client.connect(); - this.db = await client.db(); - this.addIndex(this.db.collection('project'), 'name'); - this.defaultCollection = this.db.collection('submissions'); - await this.setupIndexes(this.defaultCollection); - debug('Connected to database'); - } - catch (err) { - error(err.message); - process.exit(); - } + // Generic save record method. + async save(collectionName, item) { + const collection = this.db.collection(collectionName); + let result; + try { + debug('db.save()', collectionName); + result = await collection.findOneAndUpdate( + { _id: this.ObjectId(item._id) }, + { $set: omit(item, '_id') }, + { upsert: true, returnOriginal: false }, + ); + } catch (err) { + error(err.message); } + return result ? result.value : null; + } - // Generic save record method. - async save(collectionName, item) { - const collection = this.db.collection(collectionName); - let result; - try { - debug('db.save()', collectionName); - result = await collection.findOneAndUpdate( - {_id: this.ObjectId(item._id)}, - {$set: omit(item, '_id')}, - {upsert: true, returnOriginal: false} - ); - } - catch (err) { - error(err.message); - } - return result ? result.value : null; + // Generic load record method. + async load(collectionName) { + debug('db.load()', collectionName); + const collection = this.db.collection(collectionName); + let item; + try { + item = await collection.findOne({}); + } catch (err) { + error(err.message); } + return item; + } - // Generic load record method. - async load(collectionName) { - debug('db.load()', collectionName); - const collection = this.db.collection(collectionName); - let item; - try { - item = await collection.findOne({}); - } - catch (err) { - error(err.message); - } - return item; + // Get the collection to use for the call. + async collection(scope) { + if (scope && scope.form && scope.form.settings && scope.form.settings.collection) { + if (this.currentCollection && this.currentCollectionName === scope.form.settings.collection) { + return this.currentCollection; + } + let collection; + try { + debug('db.createCollection()', scope.form.settings.collection); + await this.db.createCollection(scope.form.settings.collection); + collection = this.db.collection(scope.form.settings.collection); + this.setupIndexes(collection, scope); + } catch (err) { + error(err.message); + } + this.currentCollection = collection || this.db.collection(scope.form.settings.collection); + this.currentCollectionName = scope.form.settings.collection; + return this.currentCollection; } + return this.defaultCollection; + } - // Get the collection to use for the call. - async collection(scope) { - if ( - scope && scope.form && scope.form.settings && scope.form.settings.collection - ) { - if (this.currentCollection && this.currentCollectionName === scope.form.settings.collection) { - return this.currentCollection; - } - let collection; - try { - debug('db.createCollection()', scope.form.settings.collection); - await this.db.createCollection(scope.form.settings.collection); - collection = this.db.collection(scope.form.settings.collection); - this.setupIndexes(collection, scope) - } - catch (err) { - error(err.message); - } - this.currentCollection = collection || this.db.collection(scope.form.settings.collection); - this.currentCollectionName = scope.form.settings.collection; - return this.currentCollection; - } - return this.defaultCollection; + /** + * Setup indexes. + */ + async setupIndexes(collection, scope) { + this.addIndex(collection, 'project'); + this.addIndex(collection, 'form'); + this.addIndex(collection, 'deleted'); + this.addIndex(collection, 'modified'); + this.addIndex(collection, 'created'); + if (scope && scope.form && scope.form.components) { + scope.utils.eachComponent(scope.form.components, (component, components, path) => { + if (component.dbIndex) { + this.addIndex(collection, `data.${path}`); + } + }); } + } - /** - * Setup indexes. - */ - async setupIndexes(collection, scope) { - this.addIndex(collection, 'project'); - this.addIndex(collection, 'form'); - this.addIndex(collection, 'deleted'); - this.addIndex(collection, 'modified'); - this.addIndex(collection, 'created'); - if (scope && scope.form && scope.form.components) { - scope.utils.eachComponent(scope.form.components, (component, components, path) => { - if (component.dbIndex) { - this.addIndex(collection, `data.${path}`); - } - }); - } + /** + * Add a field index + */ + async addIndex(collection, path) { + const index = {}; + index[path] = 1; + try { + debug('db.addIndex()', path); + collection.createIndex(index, { background: true }); + } catch (err) { + error(err.message); } + } - /** - * Add a field index - */ - async addIndex(collection, path) { - const index = {}; - index[path] = 1; - try { - debug('db.addIndex()', path); - collection.createIndex(index, {background: true}); - } - catch (err) { - error(err.message); - } + /** + * Remove a field index. + */ + async removeIndex(collection, path) { + const index = {}; + index[path] = 1; + try { + debug('db.removeIndex()', path); + collection.dropIndex(index); + } catch (err) { + error(`Cannot remove index ${path}`); } + } - /** - * Remove a field index. - */ - async removeIndex(collection, path) { - const index = {}; - index[path] = 1; - try { - debug('db.removeIndex()', path); - collection.dropIndex(index); - } - catch (err) { - error(`Cannot remove index ${path}`); - } + /** + * Fetch a list of submissions from a table/collection. + * @param {*} table + * @param {*} query + */ + async index(scope, query = {}) { + let items; + try { + debug('db.index()', query); + items = await this.find(scope, query); + } catch (err) { + error(err.message); } + return items; + } - /** - * Fetch a list of submissions from a table/collection. - * @param {*} table - * @param {*} query - */ - async index(scope, query = {}) { - let items; - try { - debug('db.index()', query); - items = await this.find(scope, query); - } - catch (err) { - error(err.message); - } - return items; + /** + * Create a new record. + */ + async create(scope, record, allowFields = []) { + record.deleted = null; + record.created = new Date(); + record.modified = new Date(); + if (scope.form && scope.form._id) { + record.form = this.ObjectId(scope.form._id); } + if (scope.project && scope.project._id) { + record.project = this.ObjectId(scope.project._id); + } + if (record.owner) { + record.owner = this.ObjectId(record.owner); + } + const collection = await this.collection(scope); + try { + debug('db.create()', record); + const result = await collection.insertOne( + pick( + record, + [ + 'data', + 'metadata', + 'modified', + 'created', + 'deleted', + 'form', + 'project', + 'owner', + 'access', + ].concat(allowFields), + ), + ); + if (!result.insertedId) { + return null; + } + return await this.read(scope, result.insertedId); + } catch (err) { + error(err.message); + } + } - /** - * Create a new record. - */ - async create(scope, record, allowFields = []) { - record.deleted = null; - record.created = new Date(); - record.modified = new Date(); - if (scope.form && scope.form._id) { - record.form = this.ObjectId(scope.form._id); - } - if (scope.project && scope.project._id) { - record.project = this.ObjectId(scope.project._id); - } - if (record.owner) { - record.owner = this.ObjectId(record.owner); - } - const collection = await this.collection(scope); - try { - debug('db.create()', record); - const result = await collection.insertOne(pick(record, [ - 'data', - 'metadata', - 'modified', - 'created', - 'deleted', - 'form', - 'project', - 'owner', - 'access' - ].concat(allowFields))); - if (!result.insertedId) { - return null; - } - return await this.read(scope, result.insertedId); - } - catch (err) { - error(err.message); - } + /** + * Return a query for a single mongo record. + * @param {*} form + * @param {*} id + * @returns + */ + query(scope, query) { + if (query._id) { + query._id = this.ObjectId(query._id); + } + if (query.owner) { + query.owner = this.ObjectId(query.owner); } + if (query.form) { + query.form = this.ObjectId(query.form); + } else if (scope.form && scope.form._id) { + query.form = this.ObjectId(scope.form._id); + } + if (scope.project && scope.project._id) { + query.project = this.ObjectId(scope.project._id); + } + query.deleted = { $eq: null }; - /** - * Return a query for a single mongo record. - * @param {*} form - * @param {*} id - * @returns - */ - query(scope, query) { - if (query._id) { - query._id = this.ObjectId(query._id); - } - if (query.owner) { - query.owner = this.ObjectId(query.owner); - } - if (query.form) { - query.form = this.ObjectId(query.form); - } - else if (scope.form && scope.form._id) { - query.form = this.ObjectId(scope.form._id); - } - if (scope.project && scope.project._id) { - query.project = this.ObjectId(scope.project._id); - } - query.deleted = {$eq: null}; + // Handle nested queries. + ['$or', '$and'].forEach((key) => { + if (query[key]) { + query[key].forEach((subQuery) => this.query(scope, subQuery)); + } + }); + return query; + } - // Handle nested queries. - ['$or', '$and'].forEach((key) => { - if (query[key]) { - query[key].forEach((subQuery) => this.query(scope, subQuery)); - } - }); - return query; + /** + * Find many records that match a query. + */ + async find(scope, query) { + try { + debug('db.find()', query); + const collection = await this.collection(scope); + return await collection.find(this.query(scope, query)).toArray(); + } catch (err) { + error(err.message); } + } - /** - * Find many records that match a query. - */ - async find(scope, query) { - try { - debug('db.find()', query); - const collection = await this.collection(scope); - return await collection.find(this.query(scope, query)).toArray(); - } - catch (err) { - error(err.message); - } + /** + * Find a record for a provided query. + */ + async findOne(scope, query) { + try { + debug('db.findOne()', query); + const collection = await this.collection(scope); + return await collection.findOne(this.query(scope, query)); + } catch (err) { + error(err.message); } + } - /** - * Find a record for a provided query. - */ - async findOne(scope, query) { - try { - debug('db.findOne()', query); - const collection = await this.collection(scope); - return await collection.findOne(this.query(scope, query)); - } - catch (err) { - error(err.message); - } + /** + * Read a single submission from a form + * + * @param {*} table + * @param {*} query + */ + async read(scope, id) { + try { + debug('db.read()', id); + const collection = await this.collection(scope); + return await collection.findOne(this.query(scope, { _id: id })); + } catch (err) { + error(err.message); } + } - /** - * Read a single submission from a form - * - * @param {*} table - * @param {*} query - */ - async read(scope, id) { - try { - debug('db.read()', id); - const collection = await this.collection(scope); - return await collection.findOne(this.query(scope, {_id: id})); - } - catch (err) { - error(err.message); - } + /** + * Update a single submission of a form. + * + * @param {*} table + * @param {*} query + */ + async update(scope, id, update, allowFields = []) { + if (!id || !update) { + return null; } - - /** - * Update a single submission of a form. - * - * @param {*} table - * @param {*} query - */ - async update(scope, id, update, allowFields = []) { - if (!id || !update) { - return null; - } - update.modified = new Date(); - try { - debug('db.update()', id, update); - const collection = await this.collection(scope); - const result = await collection.updateOne(this.query(scope, {_id: id}), { - $set: pick(update, ['data', 'metadata', 'modified'].concat(allowFields)) - }); - if (result.modifiedCount === 0) { - return null; - } - return await this.read(scope, id); - } - catch (err) { - error(err.message); - } + update.modified = new Date(); + try { + debug('db.update()', id, update); + const collection = await this.collection(scope); + const result = await collection.updateOne(this.query(scope, { _id: id }), { + $set: pick(update, ['data', 'metadata', 'modified'].concat(allowFields)), + }); + if (result.modifiedCount === 0) { + return null; + } + return await this.read(scope, id); + } catch (err) { + error(err.message); } + } - /** - * Delete a record from the database. - */ - async delete(scope, id) { - if (!id) { - return false; - } - try { - debug('db.delete()', id); - const collection = await this.collection(scope); - const result = await collection.updateOne(this.query(scope, {_id: id}), { $set: {deleted: Date.now()} }); - return result.modifiedCount > 0; - } - catch (err) { - error(err.message); - } + /** + * Delete a record from the database. + */ + async delete(scope, id) { + if (!id) { + return false; + } + try { + debug('db.delete()', id); + const collection = await this.collection(scope); + const result = await collection.updateOne(this.query(scope, { _id: id }), { + $set: { deleted: Date.now() }, + }); + return result.modifiedCount > 0; + } catch (err) { + error(err.message); } + } - /** - * Determine if a given entry is unique - */ - async isUnique(scope) {} + /** + * Determine if a given entry is unique + */ + async isUnique(scope) {} } module.exports = Database; diff --git a/src/server/index.js b/src/server/index.js index a51a5294..55ddd46c 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -1,5 +1,5 @@ module.exports = { - db: require('./db'), - auth: require('./auth'), - actions: require('./actions') -}; \ No newline at end of file + db: require('./db'), + auth: require('./auth'), + actions: require('./actions'), +}; diff --git a/src/server/package.json b/src/server/package.json index ac40523c..01f44c50 100644 --- a/src/server/package.json +++ b/src/server/package.json @@ -1,13 +1,13 @@ { - "name": "@formio/server", - "version": "0.1.0", - "description": "Core modules for the Form.io API Server", - "main": "index.js", - "dependencies": { - "async": "^3.2.4", - "bcryptjs": "^2.4.3", - "jsonwebtoken": "^9.0.0", - "lodash": "^4.17.21", - "mongodb": "^5.3.0" - } -} \ No newline at end of file + "name": "@formio/server", + "version": "0.1.0", + "description": "Core modules for the Form.io API Server", + "main": "index.js", + "dependencies": { + "async": "^3.2.4", + "bcryptjs": "^2.4.3", + "jsonwebtoken": "^9.0.0", + "lodash": "^4.17.21", + "mongodb": "^5.3.0" + } +} diff --git a/src/types/Access.ts b/src/types/Access.ts index 6e2f606f..37c3df37 100644 --- a/src/types/Access.ts +++ b/src/types/Access.ts @@ -1,20 +1,20 @@ import { RoleId } from 'types/Role'; export type Access = { - type: AccessType; - roles: RoleId[]; + type: AccessType; + roles: RoleId[]; }; export type AccessType = - | 'create_own' - | 'create_all' - | 'read_own' - | 'read_all' - | 'update_own' - | 'update_all' - | 'delete_own' - | 'delete_all' - | 'team_read' - | 'team_write' - | 'team_admin' - | 'team_access'; + | 'create_own' + | 'create_all' + | 'read_own' + | 'read_all' + | 'update_own' + | 'update_all' + | 'delete_own' + | 'delete_all' + | 'team_read' + | 'team_write' + | 'team_admin' + | 'team_access'; diff --git a/src/types/Action.ts b/src/types/Action.ts index bf2e2a9a..7c116560 100644 --- a/src/types/Action.ts +++ b/src/types/Action.ts @@ -3,21 +3,21 @@ import { FormId, RoleId } from 'types'; export type ActionId = string; export type ActionSettings = { - association: string; - type: string; - role: RoleId; + association: string; + type: string; + role: RoleId; }; export type FormAction = { - _id: ActionId; - title: string; - name: string; - handler: Array; - method: Array; - condition?: any; - priority: number; - settings: ActionSettings; - form: FormId; - // Database timestamps - deleted: Date | string; + _id: ActionId; + title: string; + name: string; + handler: Array; + method: Array; + condition?: any; + priority: number; + settings: ActionSettings; + form: FormId; + // Database timestamps + deleted: Date | string; }; diff --git a/src/types/AdvancedLogic.ts b/src/types/AdvancedLogic.ts index 99a12122..b13f8194 100644 --- a/src/types/AdvancedLogic.ts +++ b/src/types/AdvancedLogic.ts @@ -1,71 +1,75 @@ -import { RulesLogic } from "json-logic-js"; -import { SimpleConditional } from "./BaseComponent"; +import { RulesLogic } from 'json-logic-js'; +import { SimpleConditional } from './BaseComponent'; export type LogicTriggerSimple = { - type: 'simple'; - simple: SimpleConditional; + type: 'simple'; + simple: SimpleConditional; }; export type LogicTriggerJavascript = { - type: 'javascript'; - javascript: string; + type: 'javascript'; + javascript: string; }; export type LogicTriggerJson = { - type: 'json'; - json: RulesLogic; + type: 'json'; + json: RulesLogic; }; export type LogicTriggerEvent = { - type: 'event'; - event: string; + type: 'event'; + event: string; }; -export type LogicTrigger = LogicTriggerSimple | LogicTriggerJavascript | LogicTriggerJson | LogicTriggerEvent; +export type LogicTrigger = + | LogicTriggerSimple + | LogicTriggerJavascript + | LogicTriggerJson + | LogicTriggerEvent; export type LogicActionPropertyBoolean = { - type: 'property'; - property: { - type: 'boolean'; - value: string; - }, - state: boolean | 'true' | 'false'; -} + type: 'property'; + property: { + type: 'boolean'; + value: string; + }; + state: boolean | 'true' | 'false'; +}; export type LogicActionPropertyString = { - type: 'property'; - property: { - type: string; - component: string; - value: string; - }, - text: string; + type: 'property'; + property: { + type: string; + component: string; + value: string; + }; + text: string; }; export type LogicActionProperty = LogicActionPropertyBoolean | LogicActionPropertyString; export type LogicActionValue = { - type: 'value', - value: string + type: 'value'; + value: string; }; export type LogicActionMergeComponentSchema = { - type: 'mergeComponentSchema'; - schemaDefinition: any; + type: 'mergeComponentSchema'; + schemaDefinition: any; }; export type LogicActionCustomAction = { - type: 'customAction'; - customAction: string; + type: 'customAction'; + customAction: string; }; -export type LogicAction = - LogicActionProperty | - LogicActionValue | - LogicActionMergeComponentSchema | - LogicActionCustomAction; +export type LogicAction = + | LogicActionProperty + | LogicActionValue + | LogicActionMergeComponentSchema + | LogicActionCustomAction; export type AdvancedLogic = { - trigger: LogicTrigger; - actions: LogicAction[]; -}; \ No newline at end of file + trigger: LogicTrigger; + actions: LogicAction[]; +}; diff --git a/src/types/BaseComponent.ts b/src/types/BaseComponent.ts index c723cf79..4b976a44 100644 --- a/src/types/BaseComponent.ts +++ b/src/types/BaseComponent.ts @@ -1,92 +1,95 @@ -import { RulesLogic } from "json-logic-js"; -import { AdvancedLogic } from "./AdvancedLogic"; -import { getModelType } from "utils/formUtil"; -export type JSONConditional = { json: RulesLogic; }; -export type LegacyConditional = { show: boolean | string | null; when: string | null; eq: boolean | string }; -export type SimpleConditionalConditions = { component: string; operator: string; value?: any}[]; -export type SimpleConditional = { show: boolean | null; conjunction: string; conditions: SimpleConditionalConditions}; +import { RulesLogic } from 'json-logic-js'; +import { AdvancedLogic } from './AdvancedLogic'; +import { getModelType } from 'utils/formUtil'; +export type JSONConditional = { json: RulesLogic }; +export type LegacyConditional = { + show: boolean | string | null; + when: string | null; + eq: boolean | string; +}; +export type SimpleConditionalConditions = { component: string; operator: string; value?: any }[]; +export type SimpleConditional = { + show: boolean | null; + conjunction: string; + conditions: SimpleConditionalConditions; +}; export type BaseComponent = { - input: boolean; - type: string; - key: string; - path?: string; - parent?: BaseComponent; - tableView?: boolean; - placeholder?: string; - prefix?: string; - customClass?: string; - mask?: boolean; - suffix?: string; + input: boolean; + type: string; + key: string; + path?: string; + parent?: BaseComponent; + tableView?: boolean; + placeholder?: string; + prefix?: string; + customClass?: string; + mask?: boolean; + suffix?: string; + multiple?: boolean; + protected?: boolean; + unique?: boolean; + persistent?: boolean | string; + hidden?: boolean; + ephemeralState?: { + conditionallyHidden?: boolean; + }; + clearOnHide?: boolean; + refreshOn?: string; + redrawOn?: string; + modalEdit?: boolean; + label?: string; + dataGridLabel?: boolean; + labelPosition?: string; + description?: string; + errorLabel?: string; + tooltip?: string; + hideLabel?: boolean; + widget?: { type: string } | string | null; + tabindex?: string; + disabled?: boolean; + autofocus?: boolean; + dbIndex?: boolean; + defaultValue?: any; + customDefaultValue?: string; + calculateValue?: string; + calculateServer?: boolean; + attributes?: Record; + logic?: AdvancedLogic[]; + validateOn?: string; + validateWhenHidden?: boolean; + modelType?: ReturnType; + parentPath?: string; + validate?: { + required?: boolean; + custom?: string; + customPrivate?: boolean; + customMessage?: string; + strictDateValidation?: boolean; multiple?: boolean; - protected?: boolean; unique?: boolean; - persistent?: boolean | string; - hidden?: boolean; - ephemeralState?: { - conditionallyHidden?: boolean; - } - clearOnHide?: boolean; - refreshOn?: string; - redrawOn?: string; - modalEdit?: boolean; - label?: string; - dataGridLabel?: boolean; - labelPosition?: string; - description?: string; - errorLabel?: string; - tooltip?: string; - hideLabel?: boolean; - widget?: { type: string } | string | null; - tabindex?: string; - disabled?: boolean; - autofocus?: boolean; - dbIndex?: boolean; - defaultValue?: any; - customDefaultValue?: string; - calculateValue?: string; - calculateServer?: boolean; - attributes?: Record; - logic?: AdvancedLogic[]; - validateOn?: string; - validateWhenHidden?: boolean; - modelType?: ReturnType; - parentPath?: string; - validate?: { - required?: boolean; - custom?: string; - customPrivate?: boolean; - customMessage?: string; - strictDateValidation?: boolean; - multiple?: boolean; - unique?: boolean; - // TODO: we should type this as RulesLogic from the JSONLogic lib but it's giving me too many problems - json?: any; - row?: string; - }; - conditional?: - ( - JSONConditional | - LegacyConditional | - SimpleConditional - ); - customConditional?: string; - overlay?: { - style: string; - left: string; - top: string; - width: string; - height: string; - }; - allowCalculateOverride?: boolean; - encrypted?: boolean; - showCharCount?: boolean; - showWordCount?: boolean; - properties?: Record; - allowMultipleMasks?: boolean; - addons?: any[]; // TODO: this should go away - inputType?: string; - conflictId?: string; - errors?: Record; - truncateMultipleSpaces?: boolean; + // TODO: we should type this as RulesLogic from the JSONLogic lib but it's giving me too many problems + json?: any; + row?: string; + }; + conditional?: JSONConditional | LegacyConditional | SimpleConditional; + customConditional?: string; + overlay?: { + style: string; + left: string; + top: string; + width: string; + height: string; + }; + allowCalculateOverride?: boolean; + encrypted?: boolean; + showCharCount?: boolean; + showWordCount?: boolean; + properties?: Record; + allowMultipleMasks?: boolean; + addons?: any[]; // TODO: this should go away + inputType?: string; + conflictId?: string; + errors?: Record; + truncateMultipleSpaces?: boolean; }; diff --git a/src/types/Component.ts b/src/types/Component.ts index 283a76d9..46247e54 100644 --- a/src/types/Component.ts +++ b/src/types/Component.ts @@ -2,342 +2,342 @@ import * as flatpickrTypes from 'flatpickr'; import { BaseComponent } from './BaseComponent'; export type Component = - | TextFieldComponent - | NestedComponent - | ContainerComponent - | AddressComponent - | ButtonComponent - | CheckboxComponent - | ColumnsComponent - | TableComponent - | ContentComponent - | NumberComponent - | NestedArrayComponent - | DataGridComponent - | DataMapComponent - | DataSourceComponent - | DateTimeComponent - | DayComponent - | EditGridComponent - | EmailComponent - | FieldSetComponent - | FileComponent - | FormComponent - | HiddenComponent - | HtmlComponent - | PanelComponent - | PasswordComponent - | PhoneNumberComponent - | ListComponent - | RadioComponent - | RecaptchaComponent - | SelectComponent - | ResourceComponent - | SelectBoxesComponent - | SignatureComponent - | SurveyComponent - | TabsComponent - | TagsComponent - | TextAreaComponent - | TimeComponent - | UrlComponent - | WellComponent; + | TextFieldComponent + | NestedComponent + | ContainerComponent + | AddressComponent + | ButtonComponent + | CheckboxComponent + | ColumnsComponent + | TableComponent + | ContentComponent + | NumberComponent + | NestedArrayComponent + | DataGridComponent + | DataMapComponent + | DataSourceComponent + | DateTimeComponent + | DayComponent + | EditGridComponent + | EmailComponent + | FieldSetComponent + | FileComponent + | FormComponent + | HiddenComponent + | HtmlComponent + | PanelComponent + | PasswordComponent + | PhoneNumberComponent + | ListComponent + | RadioComponent + | RecaptchaComponent + | SelectComponent + | ResourceComponent + | SelectBoxesComponent + | SignatureComponent + | SurveyComponent + | TabsComponent + | TagsComponent + | TextAreaComponent + | TimeComponent + | UrlComponent + | WellComponent; export type CalendarPickerOptions = flatpickrTypes.default.Options.Options; export type BootstrapSizing = 'sm' | 'md' | 'lg' | 'xl' | 'xxl'; export type TextFieldComponent = BaseComponent & { - widget?: - | { type: 'input' } - | (CalendarPickerOptions & { - enableDate?: boolean; - format?: string; - saveAs?: string; - displayInTimezone?: string; - useLocaleSettings?: boolean; - }) - | null; - inputType?: string; - inputFormat?: string; - inputMask?: string; - inputMasks?: { label: string; mask: string }[]; - isMultipleMasksField?: boolean; - displayMask?: string; - spellcheck?: boolean; - truncateMultipleSpaces?: boolean; - validate?: { - minLength?: number | string; - maxLength?: number | string; - minWords?: number | string; - maxWords?: number | string; - pattern?: string; - patternMessage?: string; - skipMaskValidation?: boolean; - }; + widget?: + | { type: 'input' } + | (CalendarPickerOptions & { + enableDate?: boolean; + format?: string; + saveAs?: string; + displayInTimezone?: string; + useLocaleSettings?: boolean; + }) + | null; + inputType?: string; + inputFormat?: string; + inputMask?: string; + inputMasks?: { label: string; mask: string }[]; + isMultipleMasksField?: boolean; + displayMask?: string; + spellcheck?: boolean; + truncateMultipleSpaces?: boolean; + validate?: { + minLength?: number | string; + maxLength?: number | string; + minWords?: number | string; + maxWords?: number | string; + pattern?: string; + patternMessage?: string; + skipMaskValidation?: boolean; + }; }; export type NestedComponent = BaseComponent & { - tree: boolean; - lazyLoad: boolean; + tree: boolean; + lazyLoad: boolean; }; export type ContainerComponent = NestedComponent & { - clearOnHide: boolean; - tree: boolean; - hideLabel: boolean; - components: Component[]; + clearOnHide: boolean; + tree: boolean; + hideLabel: boolean; + components: Component[]; }; export type HasChildComponents = BaseComponent & { - components: Component[]; - path: string; -} + components: Component[]; + path: string; +}; export type HasRows = BaseComponent & { - path: string, - rows: { - components: Component[]; - }[][]; + path: string; + rows: { + components: Component[]; + }[][]; }; export type HasColumns = BaseComponent & { - path: string; - columns: { - components: Component[]; - }[]; -} + path: string; + columns: { + components: Component[]; + }[]; +}; export type AddressComponent = ContainerComponent & { - switchToManualModeLabel: string; - provider: string; - providerOptions: Record; - manualModeViewString: string; - disableClearIcon: boolean; - enableManualMode: boolean; + switchToManualModeLabel: string; + provider: string; + providerOptions: Record; + manualModeViewString: string; + disableClearIcon: boolean; + enableManualMode: boolean; }; export type ButtonComponent = BaseComponent & { - size: BootstrapSizing; - leftIcon: string; - rightIcon: string; - block: boolean; - action: string; - disableOnInvalid: boolean; - theme: string; + size: BootstrapSizing; + leftIcon: string; + rightIcon: string; + block: boolean; + action: string; + disableOnInvalid: boolean; + theme: string; }; export type CheckboxComponent = BaseComponent & { - value: string; - name: string; + value: string; + name: string; }; export type ColumnsComponent = NestedComponent & { - columns: { - components: Component[]; - width: number; - offset: number; - push: number; - pull: number; - size: BootstrapSizing; - }[]; - autoAdjust: boolean; + columns: { + components: Component[]; + width: number; + offset: number; + push: number; + pull: number; + size: BootstrapSizing; + }[]; + autoAdjust: boolean; }; export type TableComponent = NestedComponent & { - rows: Component[][]; - numRows: number; - numCols: number; - header: []; - caption: string; - cloneRows: boolean; - striped: boolean; - bordered: boolean; - hover: boolean; - condensed: boolean; + rows: Component[][]; + numRows: number; + numCols: number; + header: []; + caption: string; + cloneRows: boolean; + striped: boolean; + bordered: boolean; + hover: boolean; + condensed: boolean; }; export type ContentComponent = BaseComponent & { - html: string; + html: string; }; export type NumberComponent = BaseComponent & { - validate?: { - min?: number | string; - max?: number | string; - step?: 'any'; - }; - delimiter?: boolean; - requireDecimal?: boolean; - inputFormat?: string; - truncateMultipleSpaces?: boolean; + validate?: { + min?: number | string; + max?: number | string; + step?: 'any'; + }; + delimiter?: boolean; + requireDecimal?: boolean; + inputFormat?: string; + truncateMultipleSpaces?: boolean; }; export type NestedArrayComponent = NestedComponent & { - disableAddingRemovingRows: boolean; - components: Component[]; + disableAddingRemovingRows: boolean; + components: Component[]; }; export type DataGridComponent = NestedArrayComponent; export type DataMapComponent = DataGridComponent & { - addAnother: string; - disableAddingRemovingRows: boolean; - keyBeforeValue: boolean; - valueComponent: BaseComponent; + addAnother: string; + disableAddingRemovingRows: boolean; + keyBeforeValue: boolean; + valueComponent: BaseComponent; }; export type DataSourceComponent = BaseComponent & { - fetch?: { - url: string; - method: string; - headers: { key: string; value: string }[]; - authenticate: boolean; - forwardHeaders: boolean; - specifyBody: string; - mapFunction: string; - }; + fetch?: { + url: string; + method: string; + headers: { key: string; value: string }[]; + authenticate: boolean; + forwardHeaders: boolean; + specifyBody: string; + mapFunction: string; + }; }; export type DataTableComponent = EditGridComponent & { - fetch?: { - enableFetch: boolean; - dataSrc: 'resource' | 'url'; - sort?: { defaultQuery?: string }; - resource?: string; - headers?: { key: string; value: string }[]; - components?: { key: string; path: string }[] | Component[]; - } -} + fetch?: { + enableFetch: boolean; + dataSrc: 'resource' | 'url'; + sort?: { defaultQuery?: string }; + resource?: string; + headers?: { key: string; value: string }[]; + components?: { key: string; path: string }[] | Component[]; + }; +}; export type DateTimeComponent = BaseComponent & { - format?: string; - useLocaleSettings?: boolean; - allowInput?: boolean; - enableDate?: boolean; - enableTime?: boolean; - defaultDate?: string; + format?: string; + useLocaleSettings?: boolean; + allowInput?: boolean; + enableDate?: boolean; + enableTime?: boolean; + defaultDate?: string; + displayInTimezone?: string; + timezone?: string; + datepickerMode?: string; + enableMinDateInput?: boolean; + enableMaxDateInput?: boolean; + datePicker: { + showWeeks?: boolean; + startingDay?: number; + initDate?: string; + minMode?: string; + maxMode?: string; + yearRows?: number; + yearColumns?: number; + minDate?: string | null; + maxDate?: string | null; + disableWeekends?: boolean; + disableWeekdays?: boolean; + }; + timePicker?: { + hourStep?: number; + minuteStep?: number; + showMeridian?: boolean; + readonlyInput?: boolean; + mousewheel?: boolean; + arrowkeys?: boolean; + }; + widget: CalendarPickerOptions & { displayInTimezone?: string; - timezone?: string; - datepickerMode?: string; - enableMinDateInput?: boolean; - enableMaxDateInput?: boolean; - datePicker: { - showWeeks?: boolean; - startingDay?: number; - initDate?: string; - minMode?: string; - maxMode?: string; - yearRows?: number; - yearColumns?: number; - minDate?: string | null; - maxDate?: string | null; - disableWeekends?: boolean; - disableWeekdays?: boolean; - }; - timePicker?: { - hourStep?: number; - minuteStep?: number; - showMeridian?: boolean; - readonlyInput?: boolean; - mousewheel?: boolean; - arrowkeys?: boolean; - }; - widget: CalendarPickerOptions & { - displayInTimezone?: string; - useLocaleSettings?: boolean; - format?: string; - disableWeekends?: boolean; - disableWeekdays?: boolean; - }; - customOptions?: CalendarPickerOptions; + useLocaleSettings?: boolean; + format?: string; + disableWeekends?: boolean; + disableWeekdays?: boolean; + }; + customOptions?: CalendarPickerOptions; }; export type DayComponent = BaseComponent & { - fields: { - day: { - type?: string; - placeholder?: string; - required?: boolean; - hide?: boolean; - }; - month: { - type?: string; - placeholder?: string; - required?: boolean; - hide: boolean; - }; - year: { - type?: string; - placeholder?: string; - required?: boolean; - hide?: boolean; - maxYear?: string | number; - minYear?: string | number; - }; + fields: { + day: { + type?: string; + placeholder?: string; + required?: boolean; + hide?: boolean; }; - hideInputLabels?: boolean; - inputsLabelPosition?: string; - useLocaleSettings?: boolean; - dayFirst?: boolean; - maxDate?: string; - minDate?: string; - maxYear?: string | number; - minYear?: string | number; - defaultValue?: string; + month: { + type?: string; + placeholder?: string; + required?: boolean; + hide: boolean; + }; + year: { + type?: string; + placeholder?: string; + required?: boolean; + hide?: boolean; + maxYear?: string | number; + minYear?: string | number; + }; + }; + hideInputLabels?: boolean; + inputsLabelPosition?: string; + useLocaleSettings?: boolean; + dayFirst?: boolean; + maxDate?: string; + minDate?: string; + maxYear?: string | number; + minYear?: string | number; + defaultValue?: string; }; export type EditGridComponent = NestedArrayComponent & { - removeRow: string; - defaultOpen: boolean; - openWhenEmpty: boolean; - modal: boolean; - components: Component[]; - inlineEdit: boolean; - templates: { - header: string; - row: string; - tableHeader: string; - tableRow: string; - footer: string; - }; + removeRow: string; + defaultOpen: boolean; + openWhenEmpty: boolean; + modal: boolean; + components: Component[]; + inlineEdit: boolean; + templates: { + header: string; + row: string; + tableHeader: string; + tableRow: string; + footer: string; + }; }; export type EmailComponent = TextFieldComponent & { - kickbox?: { - enabled?: boolean; - }; + kickbox?: { + enabled?: boolean; + }; }; export type FieldSetComponent = NestedComponent & { components: Component[] }; export type FileComponent = BaseComponent & { - image?: boolean; - privateDownload?: boolean; - imageSize?: string; - filePattern?: string; - fileMinSize?: string; - fileMaxSize?: string; - uploadOnly?: boolean; + image?: boolean; + privateDownload?: boolean; + imageSize?: string; + filePattern?: string; + fileMinSize?: string; + fileMaxSize?: string; + uploadOnly?: boolean; }; export type FormComponent = BaseComponent & { - src: string; - reference: boolean; - form: string; - path: string; + src: string; + reference: boolean; + form: string; + path: string; }; export type HiddenComponent = BaseComponent; export type HtmlComponent = BaseComponent & { - tag: string; - attrs: Record[]; - content: string; + tag: string; + attrs: Record[]; + content: string; }; export type PanelComponent = NestedComponent & { - theme: string; - breadcrumb: string; + theme: string; + breadcrumb: string; }; export type PasswordComponent = TextFieldComponent; @@ -345,38 +345,38 @@ export type PasswordComponent = TextFieldComponent; export type PhoneNumberComponent = NumberComponent & { inputMode: 'decimal' }; export type ListComponent = BaseComponent & { - values?: { label: string; value: string; shortcut?: string }[]; - dataSrc?: string; - authenticate?: boolean; - ignoreCache?: boolean; - template?: string; - dataType?: 'auto' | 'boolean' | 'string' | 'object' | 'number'; - validate?: { - onlyAvailableItems?: boolean; - }; - valueProperty?: string; + values?: { label: string; value: string; shortcut?: string }[]; + dataSrc?: string; + authenticate?: boolean; + ignoreCache?: boolean; + template?: string; + dataType?: 'auto' | 'boolean' | 'string' | 'object' | 'number'; + validate?: { + onlyAvailableItems?: boolean; + }; + valueProperty?: string; }; type StaticValuesRadioComponent = ListComponent & { - values: { label: string; value: string; shortcut?: string }[]; - dataSrc?: "values"; - fieldSet?: boolean; - optionsLabelPosition?: string; - inline?: boolean; + values: { label: string; value: string; shortcut?: string }[]; + dataSrc?: 'values'; + fieldSet?: boolean; + optionsLabelPosition?: string; + inline?: boolean; }; type UrlValuesRadioComponent = ListComponent & { - data: { - url: string; - headers: { - key: string; - value: string; - }[]; - }; - dataSrc: 'url'; - fieldSet?: boolean; - optionsLabelPosition?: string; - inline?: boolean; + data: { + url: string; + headers: { + key: string; + value: string; + }[]; + }; + dataSrc: 'url'; + fieldSet?: boolean; + optionsLabelPosition?: string; + inline?: boolean; }; export type RadioComponent = StaticValuesRadioComponent | UrlValuesRadioComponent; @@ -384,163 +384,163 @@ export type RadioComponent = StaticValuesRadioComponent | UrlValuesRadioComponen export type RecaptchaComponent = BaseComponent; type StaticValuesSelectData = { - data: { - values: { label: string; value: string }[]; - }; - dataSrc?: undefined | 'values'; + data: { + values: { label: string; value: string }[]; + }; + dataSrc?: undefined | 'values'; }; type JsonValuesSelectData = { - data: { - json: unknown[] | string; - }; - dataSrc: 'json'; + data: { + json: unknown[] | string; + }; + dataSrc: 'json'; }; type ResourceValueSelectData = { - data: { - resource: string; - }; - dataSrc: 'resource'; + data: { + resource: string; + }; + dataSrc: 'resource'; }; type CustomValuesSelectData = { - data: { - custom: string; - }; - dataSrc: 'custom'; + data: { + custom: string; + }; + dataSrc: 'custom'; }; type UrlValuesSelectData = { - data: { - url: string; - headers: { - key: string; - value: string; - }[]; - }; - dataSrc: 'url'; + data: { + url: string; + headers: { + key: string; + value: string; + }[]; + }; + dataSrc: 'url'; }; export type SelectComponentOptions = ListComponent & { - idPath?: string; - validate?: { - select?: boolean; - }; - clearOnRefresh?: boolean; - limit?: number; - valueProperty?: string; - lazyLoad?: boolean; - filter?: string; - searchEnabled?: boolean; - searchDebounce?: number; - searchField?: string; - minSearch?: number; - readOnlyValue?: boolean; - selectFields?: string; - sort?: string; - selectThreshold?: number; - uniqueOptions?: boolean; - fuseOptions?: { - include?: string; - threshold?: number; - }; - indexeddb?: { - filter?: Record; // TODO: not sure if this is correct - }; - customOptions?: Record; // TODO: with flatpickr I type these, should I do the same with ChoicesJS? - useExactSearch?: boolean; - disableLimit?: boolean; + idPath?: string; + validate?: { + select?: boolean; + }; + clearOnRefresh?: boolean; + limit?: number; + valueProperty?: string; + lazyLoad?: boolean; + filter?: string; + searchEnabled?: boolean; + searchDebounce?: number; + searchField?: string; + minSearch?: number; + readOnlyValue?: boolean; + selectFields?: string; + sort?: string; + selectThreshold?: number; + uniqueOptions?: boolean; + fuseOptions?: { + include?: string; + threshold?: number; + }; + indexeddb?: { + filter?: Record; // TODO: not sure if this is correct + }; + customOptions?: Record; // TODO: with flatpickr I type these, should I do the same with ChoicesJS? + useExactSearch?: boolean; + disableLimit?: boolean; }; export type SelectComponent = ( - | JsonValuesSelectData - | StaticValuesSelectData - | CustomValuesSelectData - | ResourceValueSelectData - | UrlValuesSelectData + | JsonValuesSelectData + | StaticValuesSelectData + | CustomValuesSelectData + | ResourceValueSelectData + | UrlValuesSelectData ) & - SelectComponentOptions; + SelectComponentOptions; export type ResourceComponent = SelectComponent & { - resource: string; - project: string; + resource: string; + project: string; }; export type SelectBoxesComponent = RadioComponent & { - inline?: boolean; - optionsLabelPosition?: string; - defaultValue?: Record; - validate?: { - minSelectedCount?: number | string; - maxSelectedCount?: number | string; - }; - minSelectedCountMessage?: string; - maxSelectedCountMessage?: string; + inline?: boolean; + optionsLabelPosition?: string; + defaultValue?: Record; + validate?: { + minSelectedCount?: number | string; + maxSelectedCount?: number | string; + }; + minSelectedCountMessage?: string; + maxSelectedCountMessage?: string; }; export type SignatureComponent = BaseComponent & { - footer: string; - width: string; - height: string; - penColor: string; - backgroundColor: string; - minWidth: string; - maxWidth: string; - keepOverlayRatio: boolean; + footer: string; + width: string; + height: string; + penColor: string; + backgroundColor: string; + minWidth: string; + maxWidth: string; + keepOverlayRatio: boolean; }; export type SurveyComponent = BaseComponent & { - questions: { - label: string; - value: string; - tooltip: string; - }[]; - values: { - label: string; - value: string; - tooltip: string; - }[]; + questions: { + label: string; + value: string; + tooltip: string; + }[]; + values: { + label: string; + value: string; + tooltip: string; + }[]; }; export type TabsComponent = NestedComponent & { - components: { - label: string; - key: string; - components: Component[]; - }[]; - verticalLayout: boolean; + components: { + label: string; + key: string; + components: Component[]; + }[]; + verticalLayout: boolean; }; export type TagsComponent = BaseComponent & { - delimeter: string; - storeas: string; - maxTags: number; + delimeter: string; + storeas: string; + maxTags: number; }; export type TextAreaComponent = TextFieldComponent & { - rows: number; - wysiwyg: boolean; - editor: string; - fixedSize: boolean; - inputFormat: string; - as?: string; + rows: number; + wysiwyg: boolean; + editor: string; + fixedSize: boolean; + inputFormat: string; + as?: string; }; export type TimeComponent = TextFieldComponent & { - format?: string; - dataFormat: string; + format?: string; + dataFormat: string; }; export type TreeComponent = NestedComponent & { - multiple: boolean; - components: Component[]; + multiple: boolean; + components: Component[]; }; export type UrlComponent = TextFieldComponent; export type WellComponent = NestedComponent & { - components: Component[]; + components: Component[]; }; export * from './BaseComponent'; diff --git a/src/types/DataObject.ts b/src/types/DataObject.ts index c0b673b8..a58a43da 100644 --- a/src/types/DataObject.ts +++ b/src/types/DataObject.ts @@ -1,24 +1,26 @@ export type DataObject = { - [key: string]: unknown; + [key: string]: unknown; }; export type AutocompleteAddressComponentDataObject = { - mode: "autocomplete"; - address: { - [key: string]: unknown; - } -} + mode: 'autocomplete'; + address: { + [key: string]: unknown; + }; +}; export type ManualAddressComponentDataObject = { - mode: "manual"; - address: { - address1: string; - address2: string; - city: string; - state: string; - country: string; - zip: string; - } -} + mode: 'manual'; + address: { + address1: string; + address2: string; + city: string; + state: string; + country: string; + zip: string; + }; +}; -export type AddressComponentDataObject = AutocompleteAddressComponentDataObject | ManualAddressComponentDataObject; +export type AddressComponentDataObject = + | AutocompleteAddressComponentDataObject + | ManualAddressComponentDataObject; diff --git a/src/types/Form.ts b/src/types/Form.ts index f821f6d9..dc0090c3 100644 --- a/src/types/Form.ts +++ b/src/types/Form.ts @@ -3,35 +3,35 @@ import { Access, Component, ProjectId, SubmissionId } from 'types'; export type FormId = string; export interface Form { - _id?: FormId; - _vid?: number; + _id?: FormId; + _vid?: number; - title?: string; - name?: string; - path?: string; - type?: FormType; - display?: FormDisplay; - action?: string; - tags?: string[]; - access?: Access[]; - submissionAccess?: Access[]; - fieldMatchAccess?: any; - owner?: SubmissionId; - machineName?: string; - components: Component[]; - settings?: FormSettings; - properties?: Record; - project?: ProjectId; - revisions?: 'current' | 'original' | ''; - submissionRevisions?: 'true' | ''; - controller?: string; - builder?: boolean; - page?: number; + title?: string; + name?: string; + path?: string; + type?: FormType; + display?: FormDisplay; + action?: string; + tags?: string[]; + access?: Access[]; + submissionAccess?: Access[]; + fieldMatchAccess?: any; + owner?: SubmissionId; + machineName?: string; + components: Component[]; + settings?: FormSettings; + properties?: Record; + project?: ProjectId; + revisions?: 'current' | 'original' | ''; + submissionRevisions?: 'true' | ''; + controller?: string; + builder?: boolean; + page?: number; - // Database timestamps - created?: Date | string; - modified?: Date | string; - deleted?: Date | string; + // Database timestamps + created?: Date | string; + modified?: Date | string; + deleted?: Date | string; } export type FormType = 'form' | 'resource'; @@ -39,20 +39,20 @@ export type FormType = 'form' | 'resource'; export type FormDisplay = 'form' | 'pdf' | 'wizard'; export type FormSettings = { - collection?: string; - condensedMode?: boolean; - disableAutocomplete?: boolean; - fontSize?: number; - hideTitle: boolean; - layout?: string; - margins?: string; - showCheckboxBacground?: boolean; - theme?: string; - viewAsHtml?: boolean; - viewer?: string; - wizardHeaderType?: string; - pdf?: { - src: string; - id: string; - }; + collection?: string; + condensedMode?: boolean; + disableAutocomplete?: boolean; + fontSize?: number; + hideTitle: boolean; + layout?: string; + margins?: string; + showCheckboxBacground?: boolean; + theme?: string; + viewAsHtml?: boolean; + viewer?: string; + wizardHeaderType?: string; + pdf?: { + src: string; + id: string; + }; }; diff --git a/src/types/PassedComponentInstance.ts b/src/types/PassedComponentInstance.ts index 867c6468..e0f9e5d1 100644 --- a/src/types/PassedComponentInstance.ts +++ b/src/types/PassedComponentInstance.ts @@ -1,22 +1,22 @@ -import { Component } from "./Component"; -import { DataObject } from "./DataObject"; -import { Form } from "./Form"; +import { Component } from './Component'; +import { DataObject } from './DataObject'; +import { Form } from './Form'; export type PassedComponentInstance = { - evalContext: () => { - component: Component, - data: DataObject, - row: DataObject, - rowIndex: number, - iconClass: string, - t: (message: string) => string, - submission: { - data: DataObject - }, - form: Form, - options: Record, - }, - evaluate: (expression: string, additionalContext?: Record) => any, - interpolate: (text: string, additionalContext?: Record) => string, - shouldSkipValidation: (data?: DataObject, row?: DataObject) => boolean; -} + evalContext: () => { + component: Component; + data: DataObject; + row: DataObject; + rowIndex: number; + iconClass: string; + t: (message: string) => string; + submission: { + data: DataObject; + }; + form: Form; + options: Record; + }; + evaluate: (expression: string, additionalContext?: Record) => any; + interpolate: (text: string, additionalContext?: Record) => string; + shouldSkipValidation: (data?: DataObject, row?: DataObject) => boolean; +}; diff --git a/src/types/Role.ts b/src/types/Role.ts index 477a6b2a..81d74067 100644 --- a/src/types/Role.ts +++ b/src/types/Role.ts @@ -3,17 +3,17 @@ import { ProjectId } from 'types'; export type RoleId = string; export type Role = { - _id: RoleId; + _id: RoleId; - title: string; - description: string; - default: boolean; - admin: boolean; - project: ProjectId; - machineName: string; + title: string; + description: string; + default: boolean; + admin: boolean; + project: ProjectId; + machineName: string; - // Database timestamps - created: Date | string; - modified: Date | string; - delted: Date | string; + // Database timestamps + created: Date | string; + modified: Date | string; + delted: Date | string; }; diff --git a/src/types/Submission.ts b/src/types/Submission.ts index ebfdf153..3fce4f2a 100644 --- a/src/types/Submission.ts +++ b/src/types/Submission.ts @@ -3,40 +3,40 @@ import { Access, DataObject, FormId, ProjectId, RoleId } from 'types'; export type SubmissionId = string; export interface Submission { - _id: SubmissionId; - _fvid: number; + _id: SubmissionId; + _fvid: number; - form: FormId; - owner: SubmissionId; - roles: Array; - metadata: SubmissionMetadata; - data: DataObject; - project: ProjectId; - state: SubmissionState; - access: Access[]; - externalIds: Array; - externalTokens?: Array; - permission?: string; + form: FormId; + owner: SubmissionId; + roles: Array; + metadata: SubmissionMetadata; + data: DataObject; + project: ProjectId; + state: SubmissionState; + access: Access[]; + externalIds: Array; + externalTokens?: Array; + permission?: string; - // Database timestamps - created: Date | string; - modified: Date | string; - deleted?: Date | string; + // Database timestamps + created: Date | string; + modified: Date | string; + deleted?: Date | string; } export type SubmissionState = 'submitted'; export type SubmissionMetadata = { - ssoteam?: boolean; - memberCount?: number; - selectData?: any; - timezone: string; - offset: number; - origin: string; - referrer: string; - browserName: string; - userAgent: string; - pathName: string; - onLine: boolean; - headers?: Record; + ssoteam?: boolean; + memberCount?: number; + selectData?: any; + timezone: string; + offset: number; + origin: string; + referrer: string; + browserName: string; + userAgent: string; + pathName: string; + onLine: boolean; + headers?: Record; }; diff --git a/src/types/formUtil.ts b/src/types/formUtil.ts index c34fdc96..050f239f 100644 --- a/src/types/formUtil.ts +++ b/src/types/formUtil.ts @@ -1,12 +1,30 @@ -import { Component, DataObject } from "types"; +import { Component, DataObject } from 'types'; -export type EachComponentDataAsyncCallback = - (component: Component, data: DataObject, row: any, path: string, components?: Component[], index?: number, parent?: (Component | null)) => Promise; +export type EachComponentDataAsyncCallback = ( + component: Component, + data: DataObject, + row: any, + path: string, + components?: Component[], + index?: number, + parent?: Component | null, +) => Promise; -export type EachComponentDataCallback = - (component: Component, data: DataObject, row: any, path: string, components?: Component[], index?: number, parent?: (Component | null)) => boolean | void; +export type EachComponentDataCallback = ( + component: Component, + data: DataObject, + row: any, + path: string, + components?: Component[], + index?: number, + parent?: Component | null, +) => boolean | void; -export type EachComponentCallback = (component: Component, path: string, components?: Component[], parent?: Component) => boolean | void; +export type EachComponentCallback = ( + component: Component, + path: string, + components?: Component[], + parent?: Component, +) => boolean | void; export type FetchFn = (url: string, options?: RequestInit) => Promise; - diff --git a/src/types/process/ProcessConfig.ts b/src/types/process/ProcessConfig.ts index 6c0abf7b..0d8d5155 100644 --- a/src/types/process/ProcessConfig.ts +++ b/src/types/process/ProcessConfig.ts @@ -1,7 +1,7 @@ -import { Evaluator, Database } from "utils"; +import { Evaluator, Database } from 'utils'; export type ProcessConfig = { - database?: Database; - evaluator?: Evaluator; - token?: string; -} + database?: Database; + evaluator?: Evaluator; + token?: string; +}; diff --git a/src/types/process/ProcessContext.ts b/src/types/process/ProcessContext.ts index 5641bc03..5b30dc97 100644 --- a/src/types/process/ProcessContext.ts +++ b/src/types/process/ProcessContext.ts @@ -1,29 +1,29 @@ -import { - Component, - DataObject, - PassedComponentInstance, - ProcessorContext, - ProcessType, - ProcessorInfo -} from "types"; +import { + Component, + DataObject, + PassedComponentInstance, + ProcessorContext, + ProcessType, + ProcessorInfo, +} from 'types'; export type ComponentInstances = { - [key: string]: PassedComponentInstance; + [key: string]: PassedComponentInstance; }; export type BaseProcessContext = { - components: Component[]; - data: DataObject; - scope: ProcessorScope; - row?: DataObject; - instances?: ComponentInstances; - process?: ProcessType; - form?: any; - submission?: any; - flat?: boolean; - evalContext?: (context: ProcessorContext) => any; -} + components: Component[]; + data: DataObject; + scope: ProcessorScope; + row?: DataObject; + instances?: ComponentInstances; + process?: ProcessType; + form?: any; + submission?: any; + flat?: boolean; + evalContext?: (context: ProcessorContext) => any; +}; export type ProcessContext = BaseProcessContext & { - processors: ProcessorInfo[]; -}; \ No newline at end of file + processors: ProcessorInfo[]; +}; diff --git a/src/types/process/ProcessType.ts b/src/types/process/ProcessType.ts index 6f3c199b..7b766be7 100644 --- a/src/types/process/ProcessType.ts +++ b/src/types/process/ProcessType.ts @@ -1,5 +1,5 @@ export enum ProcessType { - Change = 'change', - Submit = 'submit', - Save = 'save', + Change = 'change', + Submit = 'submit', + Save = 'save', } diff --git a/src/types/process/ProcessorContext.ts b/src/types/process/ProcessorContext.ts index 8cab26e3..b4a28d51 100644 --- a/src/types/process/ProcessorContext.ts +++ b/src/types/process/ProcessorContext.ts @@ -1,25 +1,33 @@ -import { Component, DataObject, Form, PassedComponentInstance, ProcessorInfo, ProcessorScope, ProcessorType, Submission } from "types" -import { ProcessType } from "./ProcessType"; +import { + Component, + DataObject, + Form, + PassedComponentInstance, + ProcessorInfo, + ProcessorType, + Submission, +} from 'types'; +import { ProcessType } from './ProcessType'; export type ProcessorContext = { - component: Component; - path: string; - data: DataObject; - row: any; - value?: any; - form?: Form; - submission?: Submission; - components?: Component[]; - instance?: PassedComponentInstance; - process?: ProcessType; - processor?: ProcessorType; - config?: Record; - index?: number; - scope: ProcessorScope; - parent?: Component | null; - evalContext?: (context: ProcessorContext) => any; -} + component: Component; + path: string; + data: DataObject; + row: any; + value?: any; + form?: Form; + submission?: Submission; + components?: Component[]; + instance?: PassedComponentInstance; + process?: ProcessType; + processor?: ProcessorType; + config?: Record; + index?: number; + scope: ProcessorScope; + parent?: Component | null; + evalContext?: (context: ProcessorContext) => any; +}; export type ProcessorsContext = ProcessorContext & { - processors: ProcessorInfo[]; + processors: ProcessorInfo[]; }; diff --git a/src/types/process/ProcessorFn.ts b/src/types/process/ProcessorFn.ts index 481f1e87..8bf02c23 100644 --- a/src/types/process/ProcessorFn.ts +++ b/src/types/process/ProcessorFn.ts @@ -1,3 +1,5 @@ -import { ProcessorContext } from "types"; -export type ProcessorFn = (context: ProcessorContext) => Promise; +import { ProcessorContext } from 'types'; +export type ProcessorFn = ( + context: ProcessorContext, +) => Promise; export type ProcessorFnSync = (context: ProcessorContext) => void; diff --git a/src/types/process/ProcessorInfo.ts b/src/types/process/ProcessorInfo.ts index af54b5ce..74ae34aa 100644 --- a/src/types/process/ProcessorInfo.ts +++ b/src/types/process/ProcessorInfo.ts @@ -1,9 +1,9 @@ export type ProcessCheckFn = (context: ProcessorContext) => boolean; export type ProcessorInfo = { - name: string; - fullValue?: boolean; - process?: (context: ProcessorContext) => Promise; - processSync?: (context: ProcessorContext) => ProcessorReturnType; - postProcess?: (context: ProcessorContext) => void; - shouldProcess: ProcessCheckFn; -}; \ No newline at end of file + name: string; + fullValue?: boolean; + process?: (context: ProcessorContext) => Promise; + processSync?: (context: ProcessorContext) => ProcessorReturnType; + postProcess?: (context: ProcessorContext) => void; + shouldProcess: ProcessCheckFn; +}; diff --git a/src/types/process/ProcessorScope.ts b/src/types/process/ProcessorScope.ts index b4ac35e1..60bd59a3 100644 --- a/src/types/process/ProcessorScope.ts +++ b/src/types/process/ProcessorScope.ts @@ -1,3 +1,3 @@ export type ProcessorScope = { - noRecurse?: boolean; -} \ No newline at end of file + noRecurse?: boolean; +}; diff --git a/src/types/process/ProcessorType.ts b/src/types/process/ProcessorType.ts index f5553466..6e2b5cb6 100644 --- a/src/types/process/ProcessorType.ts +++ b/src/types/process/ProcessorType.ts @@ -1,4 +1,4 @@ export enum ProcessorType { - Validate = 'validate', - Custom = 'custom' + Validate = 'validate', + Custom = 'custom', } diff --git a/src/types/process/ProcessorsScope.ts b/src/types/process/ProcessorsScope.ts index 61342c81..602f2d8a 100644 --- a/src/types/process/ProcessorsScope.ts +++ b/src/types/process/ProcessorsScope.ts @@ -1,6 +1,10 @@ -import { CalculationScope } from "./calculation"; -import { ConditionsScope } from "./conditions"; -import { DefaultValueScope } from "./defaultValue"; -import { FetchScope } from "./fetch"; -import { ValidationScope } from "./validation"; -export type ProcessorsScope = CalculationScope & ConditionsScope & DefaultValueScope & FetchScope & ValidationScope; +import { CalculationScope } from './calculation'; +import { ConditionsScope } from './conditions'; +import { DefaultValueScope } from './defaultValue'; +import { FetchScope } from './fetch'; +import { ValidationScope } from './validation'; +export type ProcessorsScope = CalculationScope & + ConditionsScope & + DefaultValueScope & + FetchScope & + ValidationScope; diff --git a/src/types/process/calculation/CalculationContext.ts b/src/types/process/calculation/CalculationContext.ts index c843a7f7..0734ff65 100644 --- a/src/types/process/calculation/CalculationContext.ts +++ b/src/types/process/calculation/CalculationContext.ts @@ -1,6 +1,6 @@ -import { ProcessorContext } from "../ProcessorContext"; -import { CalculationScope } from "./CalculationScope"; +import { ProcessorContext } from '../ProcessorContext'; +import { CalculationScope } from './CalculationScope'; export type CalculationProcessContext = { - value?: any; + value?: any; }; -export type CalculationContext = ProcessorContext & CalculationProcessContext; \ No newline at end of file +export type CalculationContext = ProcessorContext & CalculationProcessContext; diff --git a/src/types/process/calculation/CalculationScope.ts b/src/types/process/calculation/CalculationScope.ts index c4c32050..b9b41c52 100644 --- a/src/types/process/calculation/CalculationScope.ts +++ b/src/types/process/calculation/CalculationScope.ts @@ -1,7 +1,7 @@ -import { ProcessorScope } from ".."; +import { ProcessorScope } from '..'; export type CalculationScope = { - calculated?: Array<{ - path: string; - value: any; - }>; -} & ProcessorScope; \ No newline at end of file + calculated?: Array<{ + path: string; + value: any; + }>; +} & ProcessorScope; diff --git a/src/types/process/calculation/index.ts b/src/types/process/calculation/index.ts index 89f6e88e..7dc93dd0 100644 --- a/src/types/process/calculation/index.ts +++ b/src/types/process/calculation/index.ts @@ -1,2 +1,2 @@ -export * from "./CalculationContext"; -export * from "./CalculationScope"; +export * from './CalculationContext'; +export * from './CalculationScope'; diff --git a/src/types/process/conditions/ConditionsContext.ts b/src/types/process/conditions/ConditionsContext.ts index c8120922..8b8bf737 100644 --- a/src/types/process/conditions/ConditionsContext.ts +++ b/src/types/process/conditions/ConditionsContext.ts @@ -1,4 +1,4 @@ -import { ProcessorContext } from "../ProcessorContext"; -import { ConditionsScope } from "./ConditionsScope"; -export type ConditionsProcessContext = {}; -export type ConditionsContext = ProcessorContext & ConditionsProcessContext; \ No newline at end of file +import { ProcessorContext } from '../ProcessorContext'; +import { ConditionsScope } from './ConditionsScope'; +export type ConditionsProcessContext = object; +export type ConditionsContext = ProcessorContext & ConditionsProcessContext; diff --git a/src/types/process/conditions/ConditionsScope.ts b/src/types/process/conditions/ConditionsScope.ts index a2570d42..12db87b5 100644 --- a/src/types/process/conditions/ConditionsScope.ts +++ b/src/types/process/conditions/ConditionsScope.ts @@ -1,7 +1,7 @@ -import { ProcessorScope } from ".."; +import { ProcessorScope } from '..'; export type ConditionsScope = { - conditionals?: Array<{ - path: string; - conditionallyHidden: boolean; - }>; -} & ProcessorScope; \ No newline at end of file + conditionals?: Array<{ + path: string; + conditionallyHidden: boolean; + }>; +} & ProcessorScope; diff --git a/src/types/process/conditions/index.ts b/src/types/process/conditions/index.ts index c0725dbd..a99fc341 100644 --- a/src/types/process/conditions/index.ts +++ b/src/types/process/conditions/index.ts @@ -1,2 +1,2 @@ -export * from "./ConditionsContext"; -export * from "./ConditionsScope"; +export * from './ConditionsContext'; +export * from './ConditionsScope'; diff --git a/src/types/process/defaultValue/DefaultValueContext.ts b/src/types/process/defaultValue/DefaultValueContext.ts index 2595a4e1..3b8e9a92 100644 --- a/src/types/process/defaultValue/DefaultValueContext.ts +++ b/src/types/process/defaultValue/DefaultValueContext.ts @@ -1,4 +1,4 @@ -import { ProcessorContext } from "../ProcessorContext"; -import { DefaultValueScope } from "./DefaultValueScope"; -export type DefaultValueProcessContext = {}; -export type DefaultValueContext = ProcessorContext & DefaultValueProcessContext; \ No newline at end of file +import { ProcessorContext } from '../ProcessorContext'; +import { DefaultValueScope } from './DefaultValueScope'; +export type DefaultValueProcessContext = object; +export type DefaultValueContext = ProcessorContext & DefaultValueProcessContext; diff --git a/src/types/process/defaultValue/DefaultValueScope.ts b/src/types/process/defaultValue/DefaultValueScope.ts index 565fb9b5..74766c74 100644 --- a/src/types/process/defaultValue/DefaultValueScope.ts +++ b/src/types/process/defaultValue/DefaultValueScope.ts @@ -1,8 +1,8 @@ -import { ProcessorScope } from ".."; +import { ProcessorScope } from '..'; export type DefaultValueScope = { - defaultValue?: any; - defaultValues?: Array<{ - path: string; - value: any; - }>; -} & ProcessorScope; \ No newline at end of file + defaultValue?: any; + defaultValues?: Array<{ + path: string; + value: any; + }>; +} & ProcessorScope; diff --git a/src/types/process/defaultValue/index.ts b/src/types/process/defaultValue/index.ts index d0a26db5..beedebce 100644 --- a/src/types/process/defaultValue/index.ts +++ b/src/types/process/defaultValue/index.ts @@ -1,2 +1,2 @@ -export * from "./DefaultValueContext"; -export * from "./DefaultValueScope"; +export * from './DefaultValueContext'; +export * from './DefaultValueScope'; diff --git a/src/types/process/fetch/FetchContext.ts b/src/types/process/fetch/FetchContext.ts index af260d98..f24729e6 100644 --- a/src/types/process/fetch/FetchContext.ts +++ b/src/types/process/fetch/FetchContext.ts @@ -1,8 +1,8 @@ -import { FetchFn } from "types/formUtil"; -import { ProcessorContext } from "../ProcessorContext"; -import { FetchScope } from "./FetchScope"; +import { FetchFn } from 'types/formUtil'; +import { ProcessorContext } from '../ProcessorContext'; +import { FetchScope } from './FetchScope'; export type FetchProcessContext = { - fetch?: FetchFn; - headers?: Record; + fetch?: FetchFn; + headers?: Record; }; -export type FetchContext = ProcessorContext & FetchProcessContext; \ No newline at end of file +export type FetchContext = ProcessorContext & FetchProcessContext; diff --git a/src/types/process/fetch/FetchScope.ts b/src/types/process/fetch/FetchScope.ts index 713e4a27..d88346fc 100644 --- a/src/types/process/fetch/FetchScope.ts +++ b/src/types/process/fetch/FetchScope.ts @@ -1,4 +1,4 @@ -import { ProcessorScope } from ".."; +import { ProcessorScope } from '..'; export type FetchScope = { - fetched?: Record; -} & ProcessorScope; \ No newline at end of file + fetched?: Record; +} & ProcessorScope; diff --git a/src/types/process/fetch/index.ts b/src/types/process/fetch/index.ts index 0c21c41f..54dba805 100644 --- a/src/types/process/fetch/index.ts +++ b/src/types/process/fetch/index.ts @@ -1,2 +1,2 @@ -export * from "./FetchContext"; -export * from "./FetchScope"; +export * from './FetchContext'; +export * from './FetchScope'; diff --git a/src/types/process/filter/FilterContext.ts b/src/types/process/filter/FilterContext.ts index 1c2ede90..2fab7707 100644 --- a/src/types/process/filter/FilterContext.ts +++ b/src/types/process/filter/FilterContext.ts @@ -1,5 +1,5 @@ -import { ProcessorContext } from "../ProcessorContext"; -import { FilterScope } from "./FilterScope"; +import { ProcessorContext } from '../ProcessorContext'; +import { FilterScope } from './FilterScope'; export type FilterContext = ProcessorContext & { - filter?: any; -}; \ No newline at end of file + filter?: any; +}; diff --git a/src/types/process/filter/FilterScope.ts b/src/types/process/filter/FilterScope.ts index e81db652..26fd3c75 100644 --- a/src/types/process/filter/FilterScope.ts +++ b/src/types/process/filter/FilterScope.ts @@ -1,8 +1,11 @@ -import { ProcessorScope } from ".."; +import { ProcessorScope } from '..'; export type FilterScope = { - filter: Record; + filter: Record< + string, + { + compModelType: string; + include: boolean; + value?: any; + } + >; } & ProcessorScope; diff --git a/src/types/process/filter/index.ts b/src/types/process/filter/index.ts index f8f9fa98..42fd7777 100644 --- a/src/types/process/filter/index.ts +++ b/src/types/process/filter/index.ts @@ -1,2 +1,2 @@ export * from './FilterContext'; -export * from './FilterScope'; \ No newline at end of file +export * from './FilterScope'; diff --git a/src/types/process/index.ts b/src/types/process/index.ts index b5c72c45..ca263e43 100644 --- a/src/types/process/index.ts +++ b/src/types/process/index.ts @@ -1,4 +1,13 @@ -import { calculateProcessInfo, conditionProcessInfo, defaultValueProcessInfo, fetchProcessInfo, filterProcessInfo, logicProcessInfo, populateProcessInfo, validateProcessInfo } from 'processes'; +import { + calculateProcessInfo, + conditionProcessInfo, + defaultValueProcessInfo, + fetchProcessInfo, + filterProcessInfo, + logicProcessInfo, + populateProcessInfo, + validateProcessInfo, +} from 'processes'; import { ProcessorInfo } from './ProcessorInfo'; export * from './ProcessType'; @@ -21,14 +30,14 @@ export * from './populate'; export * from './logic'; export const processes = { - calculation: calculateProcessInfo, - conditions: conditionProcessInfo, - defaultValue: defaultValueProcessInfo, - fetch: fetchProcessInfo, - filter: filterProcessInfo, - logic: logicProcessInfo, - populate: populateProcessInfo, - validation: validateProcessInfo -} + calculation: calculateProcessInfo, + conditions: conditionProcessInfo, + defaultValue: defaultValueProcessInfo, + fetch: fetchProcessInfo, + filter: filterProcessInfo, + logic: logicProcessInfo, + populate: populateProcessInfo, + validation: validateProcessInfo, +}; export type ProcessTarget = Record[]>; diff --git a/src/types/process/logic/LogicContext.ts b/src/types/process/logic/LogicContext.ts index f0e42637..c242a866 100644 --- a/src/types/process/logic/LogicContext.ts +++ b/src/types/process/logic/LogicContext.ts @@ -1,5 +1,5 @@ -import { ProcessorContext } from "../ProcessorContext"; -import { LogicScope } from "./LogicScope"; +import { ProcessorContext } from '../ProcessorContext'; +import { LogicScope } from './LogicScope'; export type LogicContext = ProcessorContext & { - populated?: any; -}; \ No newline at end of file + populated?: any; +}; diff --git a/src/types/process/logic/LogicScope.ts b/src/types/process/logic/LogicScope.ts index 7052e10e..2b3e9b0a 100644 --- a/src/types/process/logic/LogicScope.ts +++ b/src/types/process/logic/LogicScope.ts @@ -1,3 +1,2 @@ -import { ProcessorScope } from ".."; -export type LogicScope = { -} & ProcessorScope; \ No newline at end of file +import { ProcessorScope } from '..'; +export type LogicScope = {} & ProcessorScope; diff --git a/src/types/process/logic/index.ts b/src/types/process/logic/index.ts index 19dfa2fc..76e88f88 100644 --- a/src/types/process/logic/index.ts +++ b/src/types/process/logic/index.ts @@ -1,2 +1,2 @@ export * from './LogicContext'; -export * from './LogicScope'; \ No newline at end of file +export * from './LogicScope'; diff --git a/src/types/process/populate/PopulateContext.ts b/src/types/process/populate/PopulateContext.ts index 8b5ab46a..df71288c 100644 --- a/src/types/process/populate/PopulateContext.ts +++ b/src/types/process/populate/PopulateContext.ts @@ -1,5 +1,5 @@ -import { ProcessorContext } from "../ProcessorContext"; -import { PopulateScope } from "./PopulateScope"; +import { ProcessorContext } from '../ProcessorContext'; +import { PopulateScope } from './PopulateScope'; export type PopulateContext = ProcessorContext & { - populated?: any; -}; \ No newline at end of file + populated?: any; +}; diff --git a/src/types/process/populate/PopulateScope.ts b/src/types/process/populate/PopulateScope.ts index 7d80cc45..8f81f21a 100644 --- a/src/types/process/populate/PopulateScope.ts +++ b/src/types/process/populate/PopulateScope.ts @@ -1,9 +1,9 @@ -import { ProcessorScope } from ".."; +import { ProcessorScope } from '..'; export type PopulateScope = { - data: any; - row?: any; - populated?: Array<{ - path: string; - row: any; - }>; -} & ProcessorScope; \ No newline at end of file + data: any; + row?: any; + populated?: Array<{ + path: string; + row: any; + }>; +} & ProcessorScope; diff --git a/src/types/process/populate/index.ts b/src/types/process/populate/index.ts index 3bb24bf3..8f8106e8 100644 --- a/src/types/process/populate/index.ts +++ b/src/types/process/populate/index.ts @@ -1,2 +1,2 @@ export * from './PopulateContext'; -export * from './PopulateScope'; \ No newline at end of file +export * from './PopulateScope'; diff --git a/src/types/process/validation/ValidationContext.ts b/src/types/process/validation/ValidationContext.ts index c5acce60..9840445d 100644 --- a/src/types/process/validation/ValidationContext.ts +++ b/src/types/process/validation/ValidationContext.ts @@ -1,12 +1,12 @@ -import { ProcessorContext } from "../ProcessorContext"; -import { ValidationScope } from "./ValidationScope"; +import { ProcessorContext } from '../ProcessorContext'; +import { ValidationScope } from './ValidationScope'; import { ValidationRuleInfo } from './ValidationRuleInfo'; -import { FetchFn } from "types/formUtil"; +import { FetchFn } from 'types/formUtil'; export type SkipValidationFn = (context: ValidationContext) => boolean; export type ValidationProcessContext = { - rules?: ValidationRuleInfo[]; - skipValidation?: SkipValidationFn; - fetch?: FetchFn; - value?: any; + rules?: ValidationRuleInfo[]; + skipValidation?: SkipValidationFn; + fetch?: FetchFn; + value?: any; }; -export type ValidationContext = ProcessorContext & ValidationProcessContext; \ No newline at end of file +export type ValidationContext = ProcessorContext & ValidationProcessContext; diff --git a/src/types/process/validation/ValidationFn.ts b/src/types/process/validation/ValidationFn.ts index dcac52aa..786966c0 100644 --- a/src/types/process/validation/ValidationFn.ts +++ b/src/types/process/validation/ValidationFn.ts @@ -1,9 +1,17 @@ -import { Component } from "types/Component"; -import { DataObject } from "types/DataObject"; -import { ComponentInstances } from "../ProcessContext"; -import { FieldError } from "error"; -import { ValidationContext } from "."; -export type ValidationFn = (components: Component[], data: DataObject, instances?: ComponentInstances) => Promise; -export type ValidationFnSync = (components: Component[], data: DataObject, instances?: ComponentInstances) => FieldError[]; +import { Component } from 'types/Component'; +import { DataObject } from 'types/DataObject'; +import { ComponentInstances } from '../ProcessContext'; +import { FieldError } from 'error'; +import { ValidationContext } from '.'; +export type ValidationFn = ( + components: Component[], + data: DataObject, + instances?: ComponentInstances, +) => Promise; +export type ValidationFnSync = ( + components: Component[], + data: DataObject, + instances?: ComponentInstances, +) => FieldError[]; export type ValidationProcessorFn = (context: ValidationContext) => Promise; -export type ValidationProcessorFnSync = (context: ValidationContext) => void; \ No newline at end of file +export type ValidationProcessorFnSync = (context: ValidationContext) => void; diff --git a/src/types/process/validation/ValidationRuleInfo.ts b/src/types/process/validation/ValidationRuleInfo.ts index 08baec30..c066ccb7 100644 --- a/src/types/process/validation/ValidationRuleInfo.ts +++ b/src/types/process/validation/ValidationRuleInfo.ts @@ -1,4 +1,4 @@ -import { ValidationContext } from "."; -import { ProcessorInfo } from "../ProcessorInfo"; -import { FieldError } from "error"; -export type ValidationRuleInfo = ProcessorInfo; \ No newline at end of file +import { ValidationContext } from '.'; +import { ProcessorInfo } from '../ProcessorInfo'; +import { FieldError } from 'error'; +export type ValidationRuleInfo = ProcessorInfo; diff --git a/src/types/process/validation/ValidationScope.ts b/src/types/process/validation/ValidationScope.ts index 91addedb..0b058fe9 100644 --- a/src/types/process/validation/ValidationScope.ts +++ b/src/types/process/validation/ValidationScope.ts @@ -1,9 +1,9 @@ -import { FieldError } from "error"; -import { ProcessorScope } from ".."; +import { FieldError } from 'error'; +import { ProcessorScope } from '..'; export type ValidationScope = ProcessorScope & { - errors: FieldError[]; - validated?: Array<{ - path: string; - error: FieldError; - }>; -}; \ No newline at end of file + errors: FieldError[]; + validated?: Array<{ + path: string; + error: FieldError; + }>; +}; diff --git a/src/types/process/validation/index.ts b/src/types/process/validation/index.ts index 83bbe348..185421c9 100644 --- a/src/types/process/validation/index.ts +++ b/src/types/process/validation/index.ts @@ -1,4 +1,4 @@ export * from './ValidationScope'; export * from './ValidationContext'; export * from './ValidationRuleInfo'; -export * from './ValidationFn'; \ No newline at end of file +export * from './ValidationFn'; diff --git a/src/types/project/Project.ts b/src/types/project/Project.ts index a9fa03e1..d1dca324 100644 --- a/src/types/project/Project.ts +++ b/src/types/project/Project.ts @@ -4,103 +4,98 @@ import { ProjectSettings } from 'types/project/settings'; export type ProjectId = string; export type Project = { - _id: ProjectId; - title: string; - name: string; - type?: ProjectType; - description?: string; - tag?: string; - owner: SubmissionId; - project?: string; - remote?: any; - plan: ProjectPlan; - billing?: ProjectBilling; - apiCalls?: ProjectApiCalls; - steps: Array; - framework: ProjectFramework; - primary: boolean; - access: Access[]; - trial?: Date | string; - lastDeploy?: Date | string; - stageTitle: string; - machineName: string; - config?: Record; - protect: boolean; - settings?: ProjectSettings; - remoteSecret?: string; + _id: ProjectId; + title: string; + name: string; + type?: ProjectType; + description?: string; + tag?: string; + owner: SubmissionId; + project?: string; + remote?: any; + plan: ProjectPlan; + billing?: ProjectBilling; + apiCalls?: ProjectApiCalls; + steps: Array; + framework: ProjectFramework; + primary: boolean; + access: Access[]; + trial?: Date | string; + lastDeploy?: Date | string; + stageTitle: string; + machineName: string; + config?: Record; + protect: boolean; + settings?: ProjectSettings; + remoteSecret?: string; - formDefaults: { - revisions?: 'current' | 'original'; - }; - public?: { - custom?: { - css?: string; - js?: string; - }; - formModule?: string; + formDefaults: { + revisions?: 'current' | 'original'; + }; + public?: { + custom?: { + css?: string; + js?: string; }; + formModule?: string; + }; - // Database timestamps - created: Date | string; - modified: Date | string; - deleted: Date | string; + // Database timestamps + created: Date | string; + modified: Date | string; + deleted: Date | string; }; export type ProjectType = 'project' | 'stage' | 'tenant'; -export type ProjectPlan = - | 'basic' - | 'independent' - | 'team' - | 'trial' - | 'commercial'; +export type ProjectPlan = 'basic' | 'independent' | 'team' | 'trial' | 'commercial'; export type ProjectFramework = - | 'angular' - | 'angular2' - | 'react' - | 'vue' - | 'html5' - | 'simple' - | 'custom' - | 'aurelia' - | 'javascript'; + | 'angular' + | 'angular2' + | 'react' + | 'vue' + | 'html5' + | 'simple' + | 'custom' + | 'aurelia' + | 'javascript'; export type ProjectUsage = { - projects?: number; - tenants?: number; - stages?: number; - livestages?: number; - forms?: number; - emails?: number; - submissionRequests?: number; - formRequests?: number; - pdfs?: number; - pdfDownloads?: number; - remoteStages?: number; - apiServers?: number; - pdfServers?: number; - formManagers?: number; - vpats?: number; - submissionServers?: number; - plan?: ProjectPlan; - startDate?: string; - options?: { - sac?: boolean; - vpat?: boolean; - pdfBasic?: boolean; - }; + projects?: number; + tenants?: number; + stages?: number; + livestages?: number; + forms?: number; + emails?: number; + submissionRequests?: number; + formRequests?: number; + pdfs?: number; + pdfDownloads?: number; + remoteStages?: number; + apiServers?: number; + pdfServers?: number; + formManagers?: number; + vpats?: number; + submissionServers?: number; + plan?: ProjectPlan; + startDate?: string; + options?: { + sac?: boolean; + vpat?: boolean; + pdfBasic?: boolean; + }; }; export type ProjectBilling = { - calls: number; - checked: number; - exceeds: boolean; - usage: ProjectUsage; + calls: number; + checked: number; + exceeds: boolean; + usage: ProjectUsage; }; export type ProjectApiCalls = { - limit: ProjectUsage; - used: ProjectUsage; - reset: Date | string; + limit: ProjectUsage; + used: ProjectUsage; + reset: Date | string; }; diff --git a/src/types/project/settings/ProjectSettings.ts b/src/types/project/settings/ProjectSettings.ts index 92348efc..33d3e2b8 100644 --- a/src/types/project/settings/ProjectSettings.ts +++ b/src/types/project/settings/ProjectSettings.ts @@ -1,55 +1,51 @@ +import { ProjectLdapConfig, ProjectOauthConfig, ProjectSamlConfig } from './authorization'; import { - ProjectLdapConfig, - ProjectOauthConfig, - ProjectSamlConfig, -} from './authorization'; -import { - ProjectEmailConfig, - ProjectESignConfig, - ProjectFileStorageConfig, - ProjectGoogleDriveConfig, - ProjectKickboxConfig, - ProjectCaptchaConfig, - ProjectSQLConnectorConfig, + ProjectEmailConfig, + ProjectESignConfig, + ProjectFileStorageConfig, + ProjectGoogleDriveConfig, + ProjectKickboxConfig, + ProjectCaptchaConfig, + ProjectSQLConnectorConfig, } from './integrations'; export type ProjectSettings = { - appOrigin: string; + appOrigin: string; - // API Settings - keys?: Array<{ key: string }>; - cors: string; - csp?: string; - secret?: string; + // API Settings + keys?: Array<{ key: string }>; + cors: string; + csp?: string; + secret?: string; - // PDF settings - pdfserver?: string; - filetoken?: string; + // PDF settings + pdfserver?: string; + filetoken?: string; - // Public Configurations - allowConfig?: boolean; - allowConfigToForms?: boolean; + // Public Configurations + allowConfig?: boolean; + allowConfigToForms?: boolean; - // Custom JS & CSS - custom?: { - css?: string; - js?: string; - }; - formModule?: string; + // Custom JS & CSS + custom?: { + css?: string; + js?: string; + }; + formModule?: string; - // Integrations - email?: ProjectEmailConfig; - captcha?: ProjectCaptchaConfig; - recaptcha?: ProjectCaptchaConfig; - esign?: ProjectESignConfig; - google?: ProjectGoogleDriveConfig; - kickbox?: ProjectKickboxConfig; - sqlconnector?: ProjectSQLConnectorConfig; - storage?: ProjectFileStorageConfig; + // Integrations + email?: ProjectEmailConfig; + captcha?: ProjectCaptchaConfig; + recaptcha?: ProjectCaptchaConfig; + esign?: ProjectESignConfig; + google?: ProjectGoogleDriveConfig; + kickbox?: ProjectKickboxConfig; + sqlconnector?: ProjectSQLConnectorConfig; + storage?: ProjectFileStorageConfig; - // Authorization - tokenParse?: string; - oauth?: ProjectOauthConfig; - ldap?: ProjectLdapConfig; - saml?: ProjectSamlConfig; + // Authorization + tokenParse?: string; + oauth?: ProjectOauthConfig; + ldap?: ProjectLdapConfig; + saml?: ProjectSamlConfig; }; diff --git a/src/types/project/settings/authorization/ldap.ts b/src/types/project/settings/authorization/ldap.ts index 71e1864a..265409e0 100644 --- a/src/types/project/settings/authorization/ldap.ts +++ b/src/types/project/settings/authorization/ldap.ts @@ -1,8 +1,8 @@ // TODO: Needs review about required & optional export type ProjectLdapConfig = { - bindCredentials: string; - bindDn: string; - searchBase: string; - searchFilter: string; - url: string; + bindCredentials: string; + bindDn: string; + searchBase: string; + searchFilter: string; + url: string; }; diff --git a/src/types/project/settings/authorization/oauth.ts b/src/types/project/settings/authorization/oauth.ts index f5cbcaea..1575349d 100644 --- a/src/types/project/settings/authorization/oauth.ts +++ b/src/types/project/settings/authorization/oauth.ts @@ -1,37 +1,37 @@ import { RoleId } from 'types/Role'; export type ProjectOauthConfig = { - openid?: OpenIdOauthConfig; - github?: GithubOauthConfig; - google?: GoogleOauthConfig; + openid?: OpenIdOauthConfig; + github?: GithubOauthConfig; + google?: GoogleOauthConfig; }; export type OpenIdOauthConfig = { - authURI: string; - tokenURI: string; - clientId: string; - clientSecret: string; - authorizationMethod: 'body' | 'header'; + authURI: string; + tokenURI: string; + clientId: string; + clientSecret: string; + authorizationMethod: 'body' | 'header'; - userInfoURI: string; - scope?: string; - idPath?: string; - emailPath?: string; + userInfoURI: string; + scope?: string; + idPath?: string; + emailPath?: string; - roles: Array<{ - claim: string; - claim1: string; - value: string; - role: RoleId; - }>; + roles: Array<{ + claim: string; + claim1: string; + value: string; + role: RoleId; + }>; }; export type GithubOauthConfig = { - clientId: string; - clientSecret: string; + clientId: string; + clientSecret: string; }; export type GoogleOauthConfig = { - clientId: string; - clientSecret: string; + clientId: string; + clientSecret: string; }; diff --git a/src/types/project/settings/authorization/saml.ts b/src/types/project/settings/authorization/saml.ts index 45a31f0d..55d8a53e 100644 --- a/src/types/project/settings/authorization/saml.ts +++ b/src/types/project/settings/authorization/saml.ts @@ -2,20 +2,20 @@ import { RoleId } from 'types/Role'; // TODO: Needs review about required & optional export type ProjectSamlConfig = { - idp: string; - issuer: string; - callbackUrl: string; - passport: string; - query: string; - emailPath: string; - rolesPath: string; - rolesDelimiter: string; - profileFields: string; + idp: string; + issuer: string; + callbackUrl: string; + passport: string; + query: string; + emailPath: string; + rolesPath: string; + rolesDelimiter: string; + profileFields: string; - roles: Array<{ - formIoRole: string; - id: RoleId; - role: string; - samlRole: string; - }>; + roles: Array<{ + formIoRole: string; + id: RoleId; + role: string; + samlRole: string; + }>; }; diff --git a/src/types/project/settings/integrations/captcha.ts b/src/types/project/settings/integrations/captcha.ts index dd0ed2f0..9a064a4d 100644 --- a/src/types/project/settings/integrations/captcha.ts +++ b/src/types/project/settings/integrations/captcha.ts @@ -1,4 +1,4 @@ export type ProjectCaptchaConfig = { - siteKey: string; - secretKey: string; + siteKey: string; + secretKey: string; }; diff --git a/src/types/project/settings/integrations/dataConnections.ts b/src/types/project/settings/integrations/dataConnections.ts index f4a14bf4..e7817ffc 100644 --- a/src/types/project/settings/integrations/dataConnections.ts +++ b/src/types/project/settings/integrations/dataConnections.ts @@ -1,16 +1,16 @@ export type ProjectGoogleDriveConfig = { - clientId: string; - cskey: string; - refreshtoken: string; + clientId: string; + cskey: string; + refreshtoken: string; }; export type ProjectKickboxConfig = { - apikey: string; + apikey: string; }; export type ProjectSQLConnectorConfig = { - host: string; - password: string; - type: 'mysql' | 'mssql' | 'postgres'; - user: string; + host: string; + password: string; + type: 'mysql' | 'mssql' | 'postgres'; + user: string; }; diff --git a/src/types/project/settings/integrations/eSign.ts b/src/types/project/settings/integrations/eSign.ts index 8c45886f..2062230c 100644 --- a/src/types/project/settings/integrations/eSign.ts +++ b/src/types/project/settings/integrations/eSign.ts @@ -1,12 +1,12 @@ export type ProjectESignConfig = { - enterpriseID: string; - boxAppSettings: { - clientID: string; - clietnSecret: string; - appAuth: { - passphrase: string; - privateKey: string; - publiKeyID: string; - }; + enterpriseID: string; + boxAppSettings: { + clientID: string; + clietnSecret: string; + appAuth: { + passphrase: string; + privateKey: string; + publiKeyID: string; }; + }; }; diff --git a/src/types/project/settings/integrations/email.ts b/src/types/project/settings/integrations/email.ts index 03d96a44..2510fdb1 100644 --- a/src/types/project/settings/integrations/email.ts +++ b/src/types/project/settings/integrations/email.ts @@ -1,33 +1,33 @@ export type ProjectEmailConfig = { - smtp?: SmtpConfig; - sendgrid?: SendGridConfig; - mailgun?: MailgunConfig; + smtp?: SmtpConfig; + sendgrid?: SendGridConfig; + mailgun?: MailgunConfig; }; export type SmtpConfig = { - auth: { - user: string; - pass: string; - }; - host: string; - port: string; + auth: { + user: string; + pass: string; + }; + host: string; + port: string; }; export type SendGridConfig = { - auth: { - api_key: string; - }; + auth: { + api_key: string; + }; }; export type MailgunConfig = { - auth: { - api_key: string; - domain: string; - }; + auth: { + api_key: string; + domain: string; + }; }; export type CustomEmailConfig = { - url: string; - username: string; - password: string; + url: string; + username: string; + password: string; }; diff --git a/src/types/project/settings/integrations/fileStorage.ts b/src/types/project/settings/integrations/fileStorage.ts index 916052ea..8e0dbb0c 100644 --- a/src/types/project/settings/integrations/fileStorage.ts +++ b/src/types/project/settings/integrations/fileStorage.ts @@ -1,36 +1,36 @@ export type ProjectFileStorageConfig = { - azure?: AzureBlobConfig; - s3?: S3MinioConfig; - dropbox?: DropboxConfig; - // Need to know what type is it - // eslint-disable-next-line @typescript-eslint/no-explicit-any - google?: any; + azure?: AzureBlobConfig; + s3?: S3MinioConfig; + dropbox?: DropboxConfig; + // Need to know what type is it + // eslint-disable-next-line @typescript-eslint/no-explicit-any + google?: any; }; export type S3MinioConfig = { - AWSAccessKeyId: string; - AWSSecretKey: string; - bucket: string; - bucketUrl: string; - acl?: 'public-read' | 'private'; - encryption?: string; - expiration?: number; - region?: string; - maxSize?: number; - startsWith?: string; - minio?: boolean; + AWSAccessKeyId: string; + AWSSecretKey: string; + bucket: string; + bucketUrl: string; + acl?: 'public-read' | 'private'; + encryption?: string; + expiration?: number; + region?: string; + maxSize?: number; + startsWith?: string; + minio?: boolean; }; export type AzureBlobConfig = { - connectionString: string; - container: string; - expiration?: number; - startsWith?: string; + connectionString: string; + container: string; + expiration?: number; + startsWith?: string; }; export type DropboxConfig = { - access_token: string; - account_id: string; - token_type: string; - uid: string; + access_token: string; + account_id: string; + token_type: string; + uid: string; }; diff --git a/src/utils/Database.ts b/src/utils/Database.ts index 322ac3f0..47a344e4 100644 --- a/src/utils/Database.ts +++ b/src/utils/Database.ts @@ -1,6 +1,6 @@ import { DataObject } from 'types/DataObject'; export abstract class Database { - abstract findOne(scope: any, query: string): Promise; - abstract isUnique(data: DataObject): Promise; + abstract findOne(scope: any, query: string): Promise; + abstract isUnique(data: DataObject): Promise; } diff --git a/src/utils/Evaluator.ts b/src/utils/Evaluator.ts index 234c7fd7..3eb8da2e 100644 --- a/src/utils/Evaluator.ts +++ b/src/utils/Evaluator.ts @@ -1,187 +1,189 @@ import { noop, trim, keys, get, set, isObject, values } from 'lodash'; export interface EvaluatorOptions { - noeval?: boolean; - data?: any; + noeval?: boolean; + data?: any; } // BaseEvaluator is for extending. export class BaseEvaluator { - static templateSettings = { - interpolate: /{{([\s\S]+?)}}/g, - evaluate: /\{%([\s\S]+?)%\}/g, - escape: /\{\{\{([\s\S]+?)\}\}\}/g - }; - public static noeval: boolean = false; - public static evaluator(func: any, ...params: any) { - if (Evaluator.noeval) { - console.warn('No evaluations allowed for this renderer.'); - return noop; - } - if (typeof func === 'function') { - return func; - } - if (typeof params[0] === 'object') { - params = keys(params[0]); - } - return new Function(...params, func); - }; + static templateSettings = { + interpolate: /{{([\s\S]+?)}}/g, + evaluate: /\{%([\s\S]+?)%\}/g, + escape: /\{\{\{([\s\S]+?)\}\}\}/g, + }; + public static noeval: boolean = false; + public static evaluator(func: any, ...params: any) { + if (Evaluator.noeval) { + console.warn('No evaluations allowed for this renderer.'); + return noop; + } + if (typeof func === 'function') { + return func; + } + if (typeof params[0] === 'object') { + params = keys(params[0]); + } + return new Function(...params, func); + } - public static interpolateString(rawTemplate: string, data: any, options: EvaluatorOptions = {}) { - if (!rawTemplate) { + public static interpolateString(rawTemplate: string, data: any, options: EvaluatorOptions = {}) { + if (!rawTemplate) { + return ''; + } + if (typeof rawTemplate !== 'string') { + return (rawTemplate as any).toString(); + } + return rawTemplate.replace(/({{\s*(.*?)\s*}})/g, (match, $1, $2) => { + // If this is a function call and we allow evals. + if ($2.indexOf('(') !== -1 && !(Evaluator.noeval || options.noeval)) { + return $2.replace( + /([^(]+)\(([^)]+)\s*\);?/, + (evalMatch: any, funcName: string, args: any) => { + funcName = trim(funcName); + const func = get(data, funcName); + if (func) { + if (args) { + args = args.split(',').map((arg: string) => { + arg = trim(arg); + if (arg.indexOf('"') === 0 || arg.indexOf("'") === 0) { + return arg.substring(1, arg.length - 1); + } + return get(data, arg); + }); + } + return Evaluator.evaluate(func, args, '', false, data, options); + } return ''; + }, + ); + } else { + let dataPath = $2; + if ($2.indexOf('?') !== -1) { + dataPath = $2.replace(/\?\./g, '.'); } - if (typeof rawTemplate !== 'string') { - return (rawTemplate as any).toString(); + // Allow for conditional values. + const parts = dataPath.split('||').map((item: string) => item.trim()); + let value = ''; + let path = ''; + for (let i = 0; i < parts.length; i++) { + path = parts[i]; + value = get(data, path); + if (value) { + break; + } } - return rawTemplate.replace(/({{\s*(.*?)\s*}})/g, (match, $1, $2) => { - // If this is a function call and we allow evals. - if ($2.indexOf('(') !== -1 && !(Evaluator.noeval || options.noeval)) { - return $2.replace(/([^\(]+)\(([^\)]+)\s*\);?/, (evalMatch: any, funcName: string, args: any) => { - funcName = trim(funcName); - const func = get(data, funcName); - if (func) { - if (args) { - args = args.split(',').map((arg: string) => { - arg = trim(arg); - if ((arg.indexOf('"') === 0) || (arg.indexOf("'") === 0)) { - return arg.substring(1, arg.length - 1); - } - return get(data, arg); - }); - } - return Evaluator.evaluate(func, args, '', false, data, options); - } - return ''; - }); - } - else { - let dataPath = $2; - if ($2.indexOf('?') !== -1) { - dataPath = $2.replace(/\?\./g, '.'); - } - // Allow for conditional values. - const parts = dataPath.split('||').map((item: string) => item.trim()); - let value = ''; - let path = ''; - for (let i = 0; i < parts.length; i++) { - path = parts[i]; - value = get(data, path); - if (value) { - break; - } - } - if (options.data) { - set(options.data, path, value); - } - return value; - } - }); - } - - public static interpolate(rawTemplate: any, data: any, options: EvaluatorOptions = {}) { - if (typeof rawTemplate === 'function' && !(Evaluator.noeval || options.noeval)) { - try { - return rawTemplate(data); - } - catch (err: any) { - console.warn('Error interpolating template', err, data); - return err.message; - } + if (options.data) { + set(options.data, path, value); } + return value; + } + }); + } - return Evaluator.interpolateString(String(rawTemplate), data, options); - }; + public static interpolate(rawTemplate: any, data: any, options: EvaluatorOptions = {}) { + if (typeof rawTemplate === 'function' && !(Evaluator.noeval || options.noeval)) { + try { + return rawTemplate(data); + } catch (err: any) { + console.warn('Error interpolating template', err, data); + return err.message; + } + } - /** - * Evaluate a method. - * - * @param func - * @param args - * @return {*} - */ - public static evaluate( - func: any, - args: any = {}, - ret: any = '', - interpolate: boolean = false, - context: any = {}, - options: EvaluatorOptions = {} - ): any { - let returnVal = null; - options = isObject(options) ? options : { noeval: options }; - const component = args.component ? args.component : { key: 'unknown' }; - if (!args.form && args.instance) { - args.form = get(args.instance, 'root._form', {}); - } + return Evaluator.interpolateString(String(rawTemplate), data, options); + } - const componentKey = component.key; - if (typeof func === 'string') { - if (ret) { - func = `var ${ret};${func};return ${ret}`; - } + /** + * Evaluate a method. + * + * @param func + * @param args + * @return {*} + */ + public static evaluate( + func: any, + args: any = {}, + ret: any = '', + interpolate: boolean = false, + context: any = {}, + options: EvaluatorOptions = {}, + ): any { + let returnVal = null; + options = isObject(options) ? options : { noeval: options }; + const component = args.component ? args.component : { key: 'unknown' }; + if (!args.form && args.instance) { + args.form = get(args.instance, 'root._form', {}); + } - if (interpolate) { - func = BaseEvaluator.interpolate(func, args, options); - } + const componentKey = component.key; + if (typeof func === 'string') { + if (ret) { + func = `var ${ret};${func};return ${ret}`; + } - try { - if (Evaluator.noeval || options.noeval) { - func = noop; - } - else { - func = Evaluator.evaluator(func, args, context); - } - args = values(args); - } - catch (err) { - console.warn(`An error occured within the custom function for ${componentKey}`, err); - returnVal = null; - func = false; - } - } + if (interpolate) { + func = BaseEvaluator.interpolate(func, args, options); + } - if (typeof func === 'function') { - try { - returnVal = Evaluator.execute(func, args, context, options); - } - catch (err) { - returnVal = null; - console.warn(`An error occured within custom function for ${componentKey}`, err); - } - } - else if (func) { - console.warn(`Unknown function type for ${componentKey}`); + try { + if (Evaluator.noeval || options.noeval) { + func = noop; + } else { + func = Evaluator.evaluator(func, args, context); } - return returnVal; + args = values(args); + } catch (err) { + console.warn(`An error occured within the custom function for ${componentKey}`, err); + returnVal = null; + func = false; + } } - /** - * Execute a function. - * - * @param func - * @param args - * @returns - */ - public static execute(func: string | any, args: any, context: any = {}, options: EvaluatorOptions = {}) { - options = isObject(options) ? options : { noeval: options }; - if (Evaluator.noeval || options.noeval) { - console.warn('No evaluations allowed for this renderer.'); - return; - } - return Array.isArray(args) ? func.apply(context, args) : func.call(context, args); - }; + if (typeof func === 'function') { + try { + returnVal = Evaluator.execute(func, args, context, options); + } catch (err) { + returnVal = null; + console.warn(`An error occured within custom function for ${componentKey}`, err); + } + } else if (func) { + console.warn(`Unknown function type for ${componentKey}`); + } + return returnVal; + } + + /** + * Execute a function. + * + * @param func + * @param args + * @returns + */ + public static execute( + func: string | any, + args: any, + context: any = {}, + options: EvaluatorOptions = {}, + ) { + options = isObject(options) ? options : { noeval: options }; + if (Evaluator.noeval || options.noeval) { + console.warn('No evaluations allowed for this renderer.'); + return; + } + return Array.isArray(args) ? func.apply(context, args) : func.call(context, args); + } } // The extendable evaluator export class Evaluator extends BaseEvaluator { - /** - * Allow external modules the ability to extend the Evaluator. - * @param evaluator - */ - public static registerEvaluator(evaluator: any) { - Object.keys(evaluator).forEach((key) => { - (Evaluator as any)[key] = evaluator[key]; - }); - } + /** + * Allow external modules the ability to extend the Evaluator. + * @param evaluator + */ + public static registerEvaluator(evaluator: any) { + Object.keys(evaluator).forEach((key) => { + (Evaluator as any)[key] = evaluator[key]; + }); + } } diff --git a/src/utils/__tests__/Evaluator.test.ts b/src/utils/__tests__/Evaluator.test.ts index 26da2ae7..c4763b9d 100644 --- a/src/utils/__tests__/Evaluator.test.ts +++ b/src/utils/__tests__/Evaluator.test.ts @@ -1,160 +1,231 @@ import { Evaluator } from '../Evaluator'; import { assert } from 'chai'; -describe('Evaluator', () => { - it('Should be able to interpolate a string with Evaluator', () => { - assert.equal(Evaluator.interpolate(`{{ data.firstName }}`, { - data: { - firstName: 'Travis' - } - }), 'Travis'); - assert.equal(Evaluator.interpolate(`{{data.firstName }}`, { - data: { - firstName: 'Travis' - } - }), 'Travis'); - assert.equal(Evaluator.interpolate(`{{data.firstName}}`, { - data: { - firstName: 'Travis' - } - }), 'Travis'); - assert.equal(Evaluator.interpolate(`{{ data.firstName }}`, { - data: { - firstName: 'Travis' - } - }), 'Travis'); - assert.equal(Evaluator.interpolate(`{{ data.firstName }}`, { - data: { - firstName: 'Travis' - } - }), 'Travis'); - assert.equal(Evaluator.interpolate(`{{ data.person?.firstName }}`, { - data: { - person: { - firstName: 'Travis' - } - } - }), 'Travis'); - assert.equal(Evaluator.interpolate(`{{ data.person?.details?.bio }}`, { - data: { - person: { - firstName: 'Travis', - details: { - bio: 'Developer', - } - } - } - }), 'Developer'); - }); +describe('Evaluator', function () { + it('Should be able to interpolate a string with Evaluator', function () { + assert.equal( + Evaluator.interpolate(`{{ data.firstName }}`, { + data: { + firstName: 'Travis', + }, + }), + 'Travis', + ); + assert.equal( + Evaluator.interpolate(`{{data.firstName }}`, { + data: { + firstName: 'Travis', + }, + }), + 'Travis', + ); + assert.equal( + Evaluator.interpolate(`{{data.firstName}}`, { + data: { + firstName: 'Travis', + }, + }), + 'Travis', + ); + assert.equal( + Evaluator.interpolate(`{{ data.firstName }}`, { + data: { + firstName: 'Travis', + }, + }), + 'Travis', + ); + assert.equal( + Evaluator.interpolate(`{{ data.firstName }}`, { + data: { + firstName: 'Travis', + }, + }), + 'Travis', + ); + assert.equal( + Evaluator.interpolate(`{{ data.person?.firstName }}`, { + data: { + person: { + firstName: 'Travis', + }, + }, + }), + 'Travis', + ); + assert.equal( + Evaluator.interpolate(`{{ data.person?.details?.bio }}`, { + data: { + person: { + firstName: 'Travis', + details: { + bio: 'Developer', + }, + }, + }, + }), + 'Developer', + ); + }); - it('Should be able to evaluate an expression.', () => { - assert.equal(Evaluator.evaluate('value = data.a + data.b', { - value: 0, - data: { - a: 5, - b: 5 - } - }, 'value', true), 10); - }); + it('Should be able to evaluate an expression.', function () { + assert.equal( + Evaluator.evaluate( + 'value = data.a + data.b', + { + value: 0, + data: { + a: 5, + b: 5, + }, + }, + 'value', + true, + ), + 10, + ); + }); - it('Should work with conditional operators within it.', () => { - assert.equal(Evaluator.interpolate(`{{ data.firstName || data.lastName }}`, { - data: { - firstName: '', - lastName: 'Tidwell' - } - }), 'Tidwell'); - assert.equal(Evaluator.interpolate(`{{ data.firstName || data.lastName || data.middleName }}`, { - data: { - firstName: '', - lastName: '', - middleName: 'Joe' - } - }), 'Joe'); - assert.equal(Evaluator.interpolate(`{{ data.firstName || data.lastName || data.middleName }}`, { - data: { - firstName: 'Travis', - lastName: '', - middleName: '' - } - }), 'Travis'); - assert.equal(Evaluator.interpolate(`{{data.firstName||data.lastName||data.middleName}}`, { - data: { - firstName: '', - lastName: 'Tidwell', - middleName: '' - } - }), 'Tidwell'); - }); + it('Should work with conditional operators within it.', function () { + assert.equal( + Evaluator.interpolate(`{{ data.firstName || data.lastName }}`, { + data: { + firstName: '', + lastName: 'Tidwell', + }, + }), + 'Tidwell', + ); + assert.equal( + Evaluator.interpolate( + `{{ data.firstName || data.lastName || data.middleName }}`, + { + data: { + firstName: '', + lastName: '', + middleName: 'Joe', + }, + }, + ), + 'Joe', + ); + assert.equal( + Evaluator.interpolate( + `{{ data.firstName || data.lastName || data.middleName }}`, + { + data: { + firstName: 'Travis', + lastName: '', + middleName: '', + }, + }, + ), + 'Travis', + ); + assert.equal( + Evaluator.interpolate(`{{data.firstName||data.lastName||data.middleName}}`, { + data: { + firstName: '', + lastName: 'Tidwell', + middleName: '', + }, + }), + 'Tidwell', + ); + }); - it('Should work with functions', () => { - assert.equal(Evaluator.interpolate(`{{ printValue("firstName") }}`, { - printValue(name: string) { - return this.data[name]; - }, - data: { - firstName: 'Travis' - } - }), 'Travis'); - assert.equal(Evaluator.interpolate(`{{printValue("firstName")}}`, { - printValue(name: string) { - return this.data[name]; - }, - data: { - firstName: 'Travis' - } - }), 'Travis'); - assert.equal(Evaluator.interpolate(`{{ printValue( "firstName" ) }}`, { - printValue(name: string) { - return this.data[name]; - }, - data: { - firstName: 'Travis' - } - }), 'Travis'); - assert.equal(Evaluator.interpolate(`{{ printValue( "firstName"); }}`, { - printValue(name: string) { - return this.data[name]; - }, - data: { - firstName: 'Travis' - } - }), 'Travis'); - assert.equal(Evaluator.interpolate(`{{ printValue( data.prop); }}`, { - printValue(name: string) { - return this.data[name]; - }, - data: { - prop: 'firstName', - firstName: 'Travis' - } - }), 'Travis'); - assert.equal(Evaluator.interpolate(`{{ concat( data.prop, "lastName"); }}`, { - concat(a: string, b: string) { - return this.data[a] + ' ' + this.data[b]; - }, - data: { - prop: 'firstName', - firstName: 'Travis', - lastName: 'Tidwell' - } - }), 'Travis Tidwell'); - assert.equal(Evaluator.interpolate(`{{funcs.concat( data.a, data.b)}}`, { - funcs: { - concat(a: string, b: string) { - return this.data[a] + ' ' + this.data[b]; - } - }, - data: { - a: 'firstName', - b: 'lastName', - firstName: 'Travis', - lastName: 'Tidwell' - } - }), 'Travis Tidwell'); - assert.equal(Evaluator.interpolate(`{{ getUTCDate(date) }}`, { - date: '2021-05-02T21:00Z', - getUTCDate: (date: string) => (new Date(date)).toUTCString(), - }), 'Sun, 02 May 2021 21:00:00 GMT'); - }); + it('Should work with functions', function () { + assert.equal( + Evaluator.interpolate(`{{ printValue("firstName") }}`, { + printValue(name: string) { + return this.data[name]; + }, + data: { + firstName: 'Travis', + }, + }), + 'Travis', + ); + assert.equal( + Evaluator.interpolate(`{{printValue("firstName")}}`, { + printValue(name: string) { + return this.data[name]; + }, + data: { + firstName: 'Travis', + }, + }), + 'Travis', + ); + assert.equal( + Evaluator.interpolate(`{{ printValue( "firstName" ) }}`, { + printValue(name: string) { + return this.data[name]; + }, + data: { + firstName: 'Travis', + }, + }), + 'Travis', + ); + assert.equal( + Evaluator.interpolate(`{{ printValue( "firstName"); }}`, { + printValue(name: string) { + return this.data[name]; + }, + data: { + firstName: 'Travis', + }, + }), + 'Travis', + ); + assert.equal( + Evaluator.interpolate(`{{ printValue( data.prop); }}`, { + printValue(name: string) { + return this.data[name]; + }, + data: { + prop: 'firstName', + firstName: 'Travis', + }, + }), + 'Travis', + ); + assert.equal( + Evaluator.interpolate(`{{ concat( data.prop, "lastName"); }}`, { + concat(a: string, b: string) { + return this.data[a] + ' ' + this.data[b]; + }, + data: { + prop: 'firstName', + firstName: 'Travis', + lastName: 'Tidwell', + }, + }), + 'Travis Tidwell', + ); + assert.equal( + Evaluator.interpolate(`{{funcs.concat( data.a, data.b)}}`, { + funcs: { + concat(a: string, b: string) { + return this.data[a] + ' ' + this.data[b]; + }, + }, + data: { + a: 'firstName', + b: 'lastName', + firstName: 'Travis', + lastName: 'Tidwell', + }, + }), + 'Travis Tidwell', + ); + assert.equal( + Evaluator.interpolate(`{{ getUTCDate(date) }}`, { + date: '2021-05-02T21:00Z', + getUTCDate: (date: string) => new Date(date).toUTCString(), + }), + 'Sun, 02 May 2021 21:00:00 GMT', + ); + }); }); diff --git a/src/utils/__tests__/date.test.ts b/src/utils/__tests__/date.test.ts index b28ee832..d6fb7e25 100644 --- a/src/utils/__tests__/date.test.ts +++ b/src/utils/__tests__/date.test.ts @@ -1,15 +1,15 @@ import { expect } from 'chai'; import { formatDate } from '../date'; -describe('Test Date Utils', () => { - it('Should format date without timezone correctly', () => { +describe('Test Date Utils', function () { + it('Should format date without timezone correctly', function () { const value = '2023-04-01T12:00:00Z'; const format = 'YYYY-MM-DD'; const expected = '2023-04-01'; expect(formatDate(value, format)).to.equal(expected); }); - it('Should format date in UTC timezone correctly', () => { + it('Should format date in UTC timezone correctly', function () { const value = '2023-04-01T12:00:00Z'; const format = 'YYYY-MM-DD HH:mm:ss'; const timezone = 'UTC'; @@ -17,7 +17,7 @@ describe('Test Date Utils', () => { expect(formatDate(value, format, timezone)).to.equal(expected); }); - it('Should format date in a specific timezone correctly', () => { + it('Should format date in a specific timezone correctly', function () { const value = '2023-04-01T12:00:00Z'; const format = 'YYYY-MM-DD HH:mm:ss'; expect(formatDate(value, format, 'America/New_York')).to.equal('2023-04-01 08:00:00 EDT'); @@ -26,4 +26,4 @@ describe('Test Date Utils', () => { // expect(formatDate(value, format, 'Europe/London')).to.equal('2023-04-01 13:00:00 BST'); expect(formatDate(value, format, 'Europe/London')).to.equal('2023-04-01 13:00:00 GMT+1'); }); -}); \ No newline at end of file +}); diff --git a/src/utils/__tests__/fixtures/submission1.json b/src/utils/__tests__/fixtures/submission1.json index eecd04b6..07683486 100644 --- a/src/utils/__tests__/fixtures/submission1.json +++ b/src/utils/__tests__/fixtures/submission1.json @@ -3,9 +3,9 @@ "name": "John Smith", "age": "30", "colors": [ - {"value": "red", "label": "Red"}, - {"value": "blue", "label": "Blue"}, - {"value": "green", "label": "Green"} + { "value": "red", "label": "Red" }, + { "value": "blue", "label": "Blue" }, + { "value": "green", "label": "Green" } ], "selectboxes": { "car": false, diff --git a/src/utils/__tests__/formUtil.test.ts b/src/utils/__tests__/formUtil.test.ts index 08da3d5d..8d63350d 100644 --- a/src/utils/__tests__/formUtil.test.ts +++ b/src/utils/__tests__/formUtil.test.ts @@ -1,28 +1,8 @@ import * as fs from 'fs'; import get from 'lodash/get'; import { expect } from 'chai'; -import { - Component, - HasChildComponents, - NestedComponent, - TableComponent, -} from 'types'; -const writtenNumber = require('written-number'); -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() -); + +import { Component, HasChildComponents, TableComponent } from 'types'; import { getContextualRowData, eachComponentDataAsync, @@ -39,2157 +19,2174 @@ import { getModelType, } from '../formUtil'; -describe('eachComponent', () => { - it('should iterate through nested components in the right order', () => { - let n = 1; - eachComponent(components, (component: Component) => { - expect((component as any).order).to.equal(n); - n += 1; - }); - }); - - it('should include layouts components if provided', () => { - 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', () => { - 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); - }); - - describe('findComponent', () => { - it('should find correct component in nested structure', () => { - findComponent(components4, 'four', null, (component: Component) => { - expect(component.label).to.equal('4'); - }); - }); - it('should find correct component in flat structure', () => { - findComponent(components4, 'one', null, (component: Component) => { - expect(component.label).to.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(), +); +const components5 = JSON.parse( + fs.readFileSync(__dirname + '/fixtures/components5.json').toString(), +); +const writtenNumber = (n: number | null) => { + switch (n) { + case 1: + return 'one'; + case 2: + return 'two'; + case 3: + return 'three'; + case 4: + return 'four'; + case 5: + return 'five'; + case 6: + return 'six'; + case 7: + return 'seven'; + case 8: + return 'eight'; + default: + throw new Error('Written number does not support numbers > 8 or < 1'); + } +}; + +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 be able to find all textfield components', () => { - const comps = findComponents(components, { type: 'textfield' }); - expect(comps.length).to.equal(6); - }); - - it('Should be able to find components with special properties.', () => { - 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', () => { - 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', () => { - 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', () => { - 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', () => { - let htmlComponentsAmount = 0; - eachComponent(components5, (component: Component) => { - if (component.type === 'htmlelement') { - htmlComponentsAmount++; - } + 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); }); - expect(htmlComponentsAmount).to.be.equal(0); - }); - - it('should include `htmlelement` components when `includeAll` is provided', () => { - 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', () => { - let contentComponentsAmount = 0; - eachComponent(components5, (component: Component) => { - if (component.type === 'content') { - contentComponentsAmount++; - } + 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); }); - expect(contentComponentsAmount).to.be.equal(0); - }); - - it('should include `content` components when `includeAll` is provided', () => { - let contentComponentsAmount = 0; - eachComponent( - components5, - (component: Component) => { - if (component.type === 'content') { - contentComponentsAmount++; - } - }, - true - ); - expect(contentComponentsAmount).to.be.equal(1); - }); -}); - -describe('getComponent', () => { - it('should return the correct components', () => { - for (let n = 1; n <= 8; n += 1) { - const component = getComponent(components, writtenNumber(n)); - expect(component).not.to.be.null; - expect(component).not.to.be.undefined; - expect(component).to.be.an('object'); - expect((component as any).order).to.equal(n); - expect(component?.key).to.equal(writtenNumber(n)); - } - }); - - it('should work with a different this context', () => { - for (let n = 1; n <= 8; n += 1) { - const component = getComponent.call({}, components, writtenNumber(n)); - expect(component).not.to.be.null; - expect(component).not.to.be.undefined; - expect(component).to.be.an('object'); - expect((component as any).order).to.equal(n); - expect(component?.key).to.equal(writtenNumber(n)); - } - }); -}); - -describe('flattenComponents', () => { - it('should return an object of flattened components', () => { - const flattened = flattenComponents(components); - for (let n = 1; n <= 8; n += 1) { - const component = flattened[writtenNumber(n)]; - expect(component).not.to.be.undefined; - expect(component).to.be.an('object'); - expect((component as any).order).to.equal(n); - expect(component.key).to.equal(writtenNumber(n)); - } - }); - - it('should work with a different this context', () => { - const flattened = flattenComponents.call({}, components); - for (let n = 1; n <= 8; n += 1) { - const component = flattened[writtenNumber(n)]; - expect(component).not.to.be.undefined; - expect(component).to.be.an('object'); - expect(component.order).to.equal(n); - expect(component.key).to.equal(writtenNumber(n)); - } - }); -}); - -describe('getContextualRowData', () => { - it('Should return the data at path without the last element given nested containers', () => { - const data = { - a: { - b: { - c: 'hello', - }, - }, - }; - const path = 'a.b.c'; - const actual = getContextualRowData( - { - type: 'textfield', - input: true, - key: 'c', - }, - path, - data - ); - const expected = { c: 'hello' }; - expect(actual).to.deep.equal(expected); - }); - - it('Should return the data at path without the last element given nested containers', () => { - const data = { - a: { - b: { - c: 'hello', - }, - }, - }; - const path = 'a.b'; - const actual = getContextualRowData( - { - type: 'textfield', - input: true, - key: 'b', - }, - path, - data - ); - const expected = { b: { c: 'hello' } }; - expect(actual).to.deep.equal(expected); - }); - - it('Should return the data at path without the last element given nested containers', () => { - const data = { - a: { - b: { - c: 'hello', - }, - }, - }; - const path = 'a'; - const actual = getContextualRowData( - { - type: 'textfield', - input: true, - key: 'a', - }, - path, - data - ); - const expected = { a: { b: { c: 'hello' } } }; - expect(actual).to.deep.equal(expected); - }); - - it('Should return the data at path without the last element given nested containers', () => { - const data = { - a: { - b: { - c: 'hello', - }, - }, - d: 'there', - }; - const path = ''; - const actual = getContextualRowData( - { - type: 'textfield', - input: true, - key: 'd', - }, - path, - data - ); - const expected = { a: { b: { c: 'hello' } }, d: 'there' }; - expect(actual).to.deep.equal(expected); - }); - - it('Should return the data at path given nested arrays', () => { - const data = { - a: [ - { b: 'hello', c: 'world' }, - { b: 'foo', c: 'bar' }, - ], - }; - const path = 'a[0].b'; - const actual = getContextualRowData( - { - type: 'textfield', - input: true, - key: 'b', - }, - path, - data - ); - const expected = { b: 'hello', c: 'world' }; - expect(actual).to.deep.equal(expected); - }); - - it('Should return the data at path given nested arrays', () => { - const data = { - a: [ - { b: 'hello', c: 'world' }, - { b: 'foo', c: 'bar' }, - ], - }; - const path = 'a[1].b'; - const actual = getContextualRowData( - { - type: 'textfield', - input: true, - key: 'b', - }, - path, - data - ); - const expected = { b: 'foo', c: 'bar' }; - expect(actual).to.deep.equal(expected); - }); - - it('Should return the data at path given nested arrays', () => { - const data = { - a: [ - { b: 'hello', c: 'world' }, - { b: 'foo', c: 'bar' }, - ], - }; - const path = 'a'; - const actual = getContextualRowData( - { - type: 'textfield', - input: true, - key: 'a', - }, - path, - data - ); - const expected = { - a: [ - { b: 'hello', c: 'world' }, - { b: 'foo', c: 'bar' }, - ], - }; - expect(actual).to.deep.equal(expected); - }); - - it('Should return the data at path given nested arrays', () => { - const data = { - a: [ - { b: 'hello', c: 'world' }, - { b: 'foo', c: 'bar' }, - ], - }; - const path = ''; - const actual = getContextualRowData( - { - type: 'textfield', - input: true, - key: 'a', - }, - path, - data - ); - const expected = { - a: [ - { b: 'hello', c: 'world' }, - { b: 'foo', c: 'bar' }, - ], - }; - expect(actual).to.deep.equal(expected); - }); - - it('Should return the data at path given nested containers and arrays', () => { - const data = { - a: { - b: [ - { c: 'hello', d: 'world' }, - { c: 'foo', d: 'bar' }, - ], - }, - }; - const path = 'a.b[0].c'; - const actual = getContextualRowData( - { - type: 'textfield', - input: true, - key: 'c', - }, - path, - data - ); - const expected = { c: 'hello', d: 'world' }; - expect(actual).to.deep.equal(expected); - }); - - it('Should return the data at path given nested containers and arrays', () => { - const data = { - a: { - b: [ - { c: 'hello', d: 'world' }, - { c: 'foo', d: 'bar' }, - ], - }, - }; - const path = 'a.b[1].c'; - const actual = getContextualRowData( - { - type: 'textfield', - input: true, - key: 'c', - }, - path, - data - ); - const expected = { c: 'foo', d: 'bar' }; - expect(actual).to.deep.equal(expected); - }); - - it('Should return the data at path given nested containers and arrays', () => { - const data = { - a: { - b: [ - { c: 'hello', d: 'world' }, - { c: 'foo', d: 'bar' }, - ], - }, - }; - const path = 'a.b'; - const actual = getContextualRowData( - { - type: 'textfield', - input: true, - key: 'b', - }, - path, - data - ); - const expected = { - b: [ - { c: 'hello', d: 'world' }, - { c: 'foo', d: 'bar' }, - ], - }; - expect(actual).to.deep.equal(expected); - }); - - it('Should return the data at path given nested containers and arrays', () => { - const data = { - a: { - b: [ - { c: 'hello', d: 'world' }, - { c: 'foo', d: 'bar' }, - ], - }, - }; - const path = 'a'; - const actual = getContextualRowData( - { - type: 'textfield', - input: true, - key: 'a', - }, - path, - data - ); - const expected = { - a: { - b: [ - { c: 'hello', d: 'world' }, - { c: 'foo', d: 'bar' }, - ], - }, - }; - expect(actual).to.deep.equal(expected); - }); - - it('Should return the data at path given nested containers and arrays', () => { - const data = { - a: { - b: [ - { c: 'hello', d: 'world' }, - { c: 'foo', d: 'bar' }, - ], - }, - }; - const path = ''; - const actual = getContextualRowData( - { - type: 'textfield', - input: true, - key: 'a', - }, - path, - data - ); - const expected = { - a: { - b: [ - { c: 'hello', d: 'world' }, - { c: 'foo', d: 'bar' }, - ], - }, - }; - expect(actual).to.deep.equal(expected); - }); - - it('Should work with a component key that has periods in it', () => { - const data = { - a: { - b: [ - { c: { e: 'zed' }, d: 'world' }, - { c: { e: 'foo' }, d: 'bar' }, - ], - }, - }; - const path = 'a.b[0].c.e'; - const actual = getContextualRowData( - { - type: 'textfield', - input: true, - key: 'c.e', - }, - path, - data - ); - const expected = { c: { e: 'zed' }, d: 'world' }; - expect(actual).to.deep.equal(expected); - }); -}); -describe('eachComponentDataAsync', () => { - it('Should iterate over each component and data given a flat components array', async () => { - const components = [ - { - type: 'textfield', - key: 'textField', - label: 'Text Field', - input: true, - }, - { - type: 'textarea', - key: 'textArea', - label: 'Text Area', - input: true, - }, - ]; - const data = { - textField: 'hello', - textArea: 'world', - }; - const rowResults: Map = new Map(); - await eachComponentDataAsync( - components, - data, - async (component, data, row, path) => { - const value = get(data, path); - rowResults.set(path, [component, value]); - } - ); - expect(rowResults.size).to.equal(2); - expect(rowResults.get('textField')).to.deep.equal([ - { + 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', - label: 'Text Field', input: true, - }, - 'hello', - ]); - expect(rowResults.get('textArea')).to.deep.equal([ - { + }); + expect(rowResults.get('textArea')).to.deep.equal({ type: 'textarea', key: 'textArea', - label: 'Text Area', input: true, - }, - 'world', - ]); - }); + }); + }); - it('Should iterate over each component and data given a container component and a nested components array', async () => { - const components = [ - { - type: 'textfield', - key: 'textField', - label: 'Text Field', - input: true, - }, - { - type: 'container', - key: 'container', - label: 'Container', - input: true, - components: [ - { - type: 'textfield', - key: 'nestedTextField', - label: 'Nested Text Field', - input: true, - }, - { - type: 'textarea', - key: 'nestedTextArea', - label: 'Nested Text Area', - input: true, - }, - ], - }, - ]; - const data = { - textField: 'hello', - container: { - nestedTextField: 'world', - nestedTextArea: 'foo', - }, - }; - const rowResults: Map = new Map(); - await eachComponentDataAsync( - components, - data, - async (component, data, row, path) => { - const value = get(data, path); - rowResults.set(path, [component, value]); - } - ); - expect(rowResults.size).to.equal(4); - expect(rowResults.get('textField')).to.deep.equal([ - { + 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', - label: 'Text Field', input: true, - }, - 'hello', - ]); - expect(rowResults.get('container')).to.deep.equal([ - { + }); + expect(rowResults.get('container')).to.deep.equal({ type: 'container', key: 'container', - label: 'Container', input: true, components: [ { type: 'textfield', key: 'nestedTextField', - label: 'Nested Text Field', input: true, }, { type: 'textarea', key: 'nestedTextArea', - label: 'Nested Text Area', input: true, }, ], - }, - { - nestedTextField: 'world', - nestedTextArea: 'foo', - }, - ]); - expect(rowResults.get('container.nestedTextField')).to.deep.equal([ - { + }); + expect(rowResults.get('container.nestedTextField')).to.deep.equal({ type: 'textfield', key: 'nestedTextField', - label: 'Nested Text Field', input: true, - }, - 'world', - ]); - expect(rowResults.get('container.nestedTextArea')).to.deep.equal([ - { + }); + expect(rowResults.get('container.nestedTextArea')).to.deep.equal({ type: 'textarea', key: 'nestedTextArea', - label: 'Nested Text Area', input: true, - }, - 'foo', - ]); - }); + }); + }); - it('Should iterate over each component and data given a datagrid component and a nested components array', async () => { - const components = [ - { - type: 'textfield', - key: 'textField', - label: 'Text Field', - input: true, - }, - { - type: 'datagrid', - key: 'dataGrid', - label: 'Data Grid', - input: true, - components: [ - { - type: 'textfield', - key: 'nestedTextField', - label: 'Nested Text Field', - input: true, - }, - { - type: 'textarea', - key: 'nestedTextArea', - label: 'Nested Text Area', - input: true, - }, - ], - }, - ]; - const data = { - textField: 'hello', - dataGrid: [ + it('Should iterate over each component with correct pathing given a datagrid component', function () { + const components = [ { - nestedTextField: 'world', - nestedTextArea: 'foo', + type: 'textfield', + key: 'textField', + input: true, }, { - nestedTextField: 'bar', - nestedTextArea: 'baz', - }, - ], - }; - const rowResults: Map = new Map(); - await eachComponentDataAsync( - components, - data, - async (component, data, row, path) => { - const value = get(data, path); - rowResults.set(path, [component, value]); - } - ); - expect(rowResults.size).to.equal(6); - expect(rowResults.get('textField')).to.deep.equal([ - { + 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', - label: 'Text Field', input: true, - }, - 'hello', - ]); - expect(rowResults.get('dataGrid')).to.deep.equal([ - { + }); + expect(rowResults.get('dataGrid')).to.deep.equal({ type: 'datagrid', key: 'dataGrid', - label: 'Data Grid', input: true, components: [ { type: 'textfield', key: 'nestedTextField', - label: 'Nested Text Field', input: true, }, { type: 'textarea', key: 'nestedTextArea', - label: 'Nested Text Area', input: true, }, ], - }, - [ - { - nestedTextField: 'world', - nestedTextArea: 'foo', - }, - { - nestedTextField: 'bar', - nestedTextArea: 'baz', - }, - ], - ]); - expect(rowResults.get('dataGrid[0].nestedTextField')).to.deep.equal([ - { + }); + expect(rowResults.get('dataGrid.nestedTextField')).to.deep.equal({ type: 'textfield', key: 'nestedTextField', - label: 'Nested Text Field', - input: true, - }, - 'world', - ]); - }); - - it('Should iterate over a components array and include components that are not in the data object if the includeAll flag is set to true', async () => { - const components = [ - { - type: 'textfield', - key: 'textField', - label: 'Text Field', - input: true, - }, - { - type: 'textarea', - key: 'textArea', - label: 'Text Area', - input: true, - }, - ]; - const data = { - textField: 'hello', - }; - const rowResults: Map = new Map(); - await eachComponentDataAsync( - components, - data, - async (component, data, row, path) => { - const value = get(data, path); - rowResults.set(path, [component, value]); - }, - undefined, - undefined, - undefined, - true - ); - expect(rowResults.size).to.equal(2); - expect(rowResults.get('textField')).to.deep.equal([ - { - type: 'textfield', - key: 'textField', - label: 'Text Field', input: true, - }, - 'hello', - ]); - expect(rowResults.get('textArea')).to.deep.equal([ - { + }); + expect(rowResults.get('dataGrid.nestedTextArea')).to.deep.equal({ type: 'textarea', - key: 'textArea', - label: 'Text Area', + key: 'nestedTextArea', input: true, - }, - undefined, - ]); - }); - - describe('Flattened form components (for evaluation)', () => { - it('Should return the correct contextual row data for each component', async () => { - const components = [ - { - type: 'textfield', - key: 'textField', - input: true, - tableView: true, - }, - { - type: 'datagrid', - key: 'dataGrid', - input: true, - tableView: true, - }, - { - type: 'textfield', - key: 'dataGrid[0].nestedTextField', - input: true, - tableView: true, - }, - { - type: 'editgrid', - key: 'dataGrid[0].nestedEditGrid', - input: true, - tableView: true, - }, - { - type: 'textfield', - key: 'dataGrid[0].nestedEditGrid[0].nestedNestedTextField', - input: true, - tableView: true, - }, - ]; - const data = { - textField: 'hello', - dataGrid: [ - { - nestedTextField: 'world', - nestedEditGrid: [ - { - nestedNestedTextField: 'foo', - }, - ], - }, - { - nestedTextField: 'bar', - nestedEditGrid: [ - { - nestedNestedTextField: 'baz', - }, - ], - }, - ], - }; - const rowResults: Map = new Map(); - await eachComponentDataAsync( - components, - data, - async (component, data, row, path) => { - rowResults.set(path, row); - } - ); - console.log(rowResults); + }); }); - }); - describe('Normal form components', () => { - it('Should return the correct contextual row data for each component', async () => { + it("Should iterate over each component with correct pathing given a datagrid's child components", function () { const components = [ - { - type: 'textfield', - key: 'textField', - input: true, - tableView: true, - }, { type: 'datagrid', key: 'dataGrid', input: true, - tableView: true, components: [ { type: 'textfield', key: 'nestedTextField', input: true, - tableView: true, }, { - type: 'editGrid', - key: 'nestedEditGrid', + type: 'textarea', + key: 'nestedTextArea', input: true, - tableView: true, - components: [ - { - type: 'textfield', - key: 'nestedNestedTextField', - input: true, - tableView: true, - }, - ], }, ], }, ]; - const data = { - textField: 'hello', - dataGrid: [ - { - nestedTextField: 'world', - nestedEditGrid: [ - { - nestedNestedTextField: 'foo', - }, - ], - }, - { - nestedTextField: 'bar', - nestedEditGrid: [ - { - nestedNestedTextField: 'baz', - }, - ], - }, - ], - }; const rowResults: Map = new Map(); - await eachComponentDataAsync( + 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, - data, - async (component, data, row, path) => { - rowResults.set(path, row); + (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, ); - console.log(rowResults); + expect(htmlComponentsAmount).to.be.equal(1); }); - }); -}); -describe('isComponentDataEmpty', () => { - it('Should return true for an empty object', () => { - const component = { - type: 'textfield', - input: true, - key: 'textField', - }; - const data = {}; - const actual = isComponentDataEmpty(component, data, 'textField'); - const expected = true; - expect(actual).to.equal(expected); - }); + 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 return false for a non-empty object', () => { - const component = { - type: 'textfield', - input: true, - key: 'textField', - }; - const data = { - textField: 'hello', - }; - const actual = isComponentDataEmpty(component, data, 'textField'); - const expected = false; - expect(actual).to.equal(expected); + 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); + }); }); - it('Should return true for a checkbox component set to false', () => { - const component = { - type: 'checkbox', - input: true, - key: 'checkbox', - }; - const data = { - checkbox: false, - }; - const actual = isComponentDataEmpty(component, data, 'checkbox'); - const expected = true; - expect(actual).to.equal(expected); - }); + describe('getComponent', function () { + it('should return the correct components', function () { + for (let n = 1; n <= 8; n += 1) { + const component = getComponent(components, writtenNumber(n)); + expect(component).not.to.equal(null); + expect(component).not.to.equal(undefined); + expect(component).to.be.an('object'); + expect((component as any).order).to.equal(n); + expect(component?.key).to.equal(writtenNumber(n)); + } + }); - it('Should return false for a checkbox component set to true', () => { - const component = { - type: 'checkbox', - input: true, - key: 'checkbox', - }; - const data = { - checkbox: true, - }; - const actual = isComponentDataEmpty(component, data, 'checkbox'); - const expected = false; - expect(actual).to.equal(expected); + it('should work with a different this context', function () { + for (let n = 1; n <= 8; n += 1) { + const component = getComponent.call({}, components, writtenNumber(n)); + expect(component).not.to.equal(null); + expect(component).not.to.equal(undefined); + expect(component).to.be.an('object'); + expect((component as any).order).to.equal(n); + expect(component?.key).to.equal(writtenNumber(n)); + } + }); }); - it('Should return true for an empty dataGrid component', () => { - const component = { - type: 'datagrid', - input: true, - key: 'dataGrid', - }; - const data = { - dataGrid: [], - }; - const actual = isComponentDataEmpty(component, data, 'dataGrid'); - const expected = true; - expect(actual).to.equal(expected); + describe('flattenComponents', function () { + it('should return an object of flattened components', function () { + const flattened = flattenComponents(components); + for (let n = 1; n <= 8; n += 1) { + const component = flattened[writtenNumber(n)]; + expect(component).not.to.equal(undefined); + expect(component).to.be.an('object'); + expect((component as any).order).to.equal(n); + expect(component.key).to.equal(writtenNumber(n)); + } + }); + + it('should work with a different this context', function () { + const flattened = flattenComponents.call({}, components); + for (let n = 1; n <= 8; n += 1) { + const component = flattened[writtenNumber(n)]; + expect(component).not.to.equal(undefined); + expect(component).to.be.an('object'); + expect(component.order).to.equal(n); + expect(component.key).to.equal(writtenNumber(n)); + } + }); }); - it('Should return true for a non-empty dataGrid component with empty child components', () => { - const component = { - type: 'datagrid', - input: true, - key: 'dataGrid', - components: [ + describe('getContextualRowData', function () { + it('Should return the data at path without the last element given nested containers', function () { + const data = { + a: { + b: { + c: 'hello', + }, + }, + }; + const path = 'a.b.c'; + const actual = getContextualRowData( { type: 'textfield', input: true, - key: 'textField', + key: 'c', + }, + path, + data, + ); + const expected = { c: 'hello' }; + expect(actual).to.deep.equal(expected); + }); + + it('Should return the data at path without the last element given nested containers and a nested path', function () { + const data = { + a: { + b: { + c: 'hello', + }, }, + }; + const path = 'a.b'; + const actual = getContextualRowData( { - type: 'checkbox', + type: 'textfield', input: true, - key: 'checkbox', + key: 'b', + }, + path, + data, + ); + const expected = { b: { c: 'hello' } }; + expect(actual).to.deep.equal(expected); + }); + + it('Should return the data at path without the last element given nested containers and a simple path', function () { + const data = { + a: { + b: { + c: 'hello', + }, }, + }; + const path = 'a'; + const actual = getContextualRowData( { - type: 'textarea', - wysiwyg: true, + type: 'textfield', input: true, - key: 'textArea', + key: 'a', }, - ], - }; - const data = { - dataGrid: [ - { - textField: '', - checkbox: false, - textArea: '

 

', - }, - ], - }; - const actual = isComponentDataEmpty(component, data, 'dataGrid'); - const expected = true; - expect(actual).to.equal(expected); - }); + path, + data, + ); + const expected = { a: { b: { c: 'hello' } } }; + expect(actual).to.deep.equal(expected); + }); - it('Should return false for a datagrid with non-empty child components', () => { - const component = { - type: 'datagrid', - input: true, - key: 'dataGrid', - components: [ + it('Should return the data at path without the last element given nested containers and a blank path', function () { + const data = { + a: { + b: { + c: 'hello', + }, + }, + d: 'there', + }; + const path = ''; + const actual = getContextualRowData( { type: 'textfield', input: true, - key: 'textField', + key: 'd', }, + path, + data, + ); + const expected = { a: { b: { c: 'hello' } }, d: 'there' }; + expect(actual).to.deep.equal(expected); + }); + + it('Should return the data at path given nested arrays', function () { + const data = { + a: [ + { b: 'hello', c: 'world' }, + { b: 'foo', c: 'bar' }, + ], + }; + const path = 'a[0].b'; + const actual = getContextualRowData( { - type: 'checkbox', + type: 'textfield', input: true, - key: 'checkbox', + key: 'b', }, - { + path, + data, + ); + const expected = { b: 'hello', c: 'world' }; + expect(actual).to.deep.equal(expected); + }); + + it('Should return the data at path given nested arrays and a nested path', function () { + const data = { + a: [ + { b: 'hello', c: 'world' }, + { b: 'foo', c: 'bar' }, + ], + }; + const path = 'a[1].b'; + const actual = getContextualRowData( + { + type: 'textfield', + input: true, + key: 'b', + }, + path, + data, + ); + const expected = { b: 'foo', c: 'bar' }; + expect(actual).to.deep.equal(expected); + }); + + it('Should return the data at path given nested arrays and a simple path', function () { + const data = { + a: [ + { b: 'hello', c: 'world' }, + { b: 'foo', c: 'bar' }, + ], + }; + const path = 'a'; + const actual = getContextualRowData( + { + type: 'textfield', + input: true, + key: 'a', + }, + path, + data, + ); + const expected = { + a: [ + { b: 'hello', c: 'world' }, + { b: 'foo', c: 'bar' }, + ], + }; + expect(actual).to.deep.equal(expected); + }); + + it('Should return the data at path given nested arrays and a blank path', function () { + const data = { + a: [ + { b: 'hello', c: 'world' }, + { b: 'foo', c: 'bar' }, + ], + }; + const path = ''; + const actual = getContextualRowData( + { + type: 'textfield', + input: true, + key: 'a', + }, + path, + data, + ); + const expected = { + a: [ + { b: 'hello', c: 'world' }, + { b: 'foo', c: 'bar' }, + ], + }; + expect(actual).to.deep.equal(expected); + }); + + it('Should return the data at path given nested containers and arrays', function () { + const data = { + a: { + b: [ + { c: 'hello', d: 'world' }, + { c: 'foo', d: 'bar' }, + ], + }, + }; + const path = 'a.b[0].c'; + const actual = getContextualRowData( + { + type: 'textfield', + input: true, + key: 'c', + }, + path, + data, + ); + const expected = { c: 'hello', d: 'world' }; + expect(actual).to.deep.equal(expected); + }); + + it('Should return the data at path given nested containers and arrays and a nested path', function () { + const data = { + a: { + b: [ + { c: 'hello', d: 'world' }, + { c: 'foo', d: 'bar' }, + ], + }, + }; + const path = 'a.b[1].c'; + const actual = getContextualRowData( + { + type: 'textfield', + input: true, + key: 'c', + }, + path, + data, + ); + const expected = { c: 'foo', d: 'bar' }; + expect(actual).to.deep.equal(expected); + }); + + it('Should return the data at path given nested containers and arrays and a different nested path', function () { + const data = { + a: { + b: [ + { c: 'hello', d: 'world' }, + { c: 'foo', d: 'bar' }, + ], + }, + }; + const path = 'a.b'; + const actual = getContextualRowData( + { + type: 'textfield', + input: true, + key: 'b', + }, + path, + data, + ); + const expected = { + b: [ + { c: 'hello', d: 'world' }, + { c: 'foo', d: 'bar' }, + ], + }; + expect(actual).to.deep.equal(expected); + }); + + it('Should return the data at path given nested containers and arrays and a simple path', function () { + const data = { + a: { + b: [ + { c: 'hello', d: 'world' }, + { c: 'foo', d: 'bar' }, + ], + }, + }; + const path = 'a'; + const actual = getContextualRowData( + { + type: 'textfield', + input: true, + key: 'a', + }, + path, + data, + ); + const expected = { + a: { + b: [ + { c: 'hello', d: 'world' }, + { c: 'foo', d: 'bar' }, + ], + }, + }; + expect(actual).to.deep.equal(expected); + }); + + it('Should return the data at path given nested containers and arrays and a blank path', function () { + const data = { + a: { + b: [ + { c: 'hello', d: 'world' }, + { c: 'foo', d: 'bar' }, + ], + }, + }; + const path = ''; + const actual = getContextualRowData( + { + type: 'textfield', + input: true, + key: 'a', + }, + path, + data, + ); + const expected = { + a: { + b: [ + { c: 'hello', d: 'world' }, + { c: 'foo', d: 'bar' }, + ], + }, + }; + expect(actual).to.deep.equal(expected); + }); + + it('Should work with a component key that has periods in it', function () { + const data = { + a: { + b: [ + { c: { e: 'zed' }, d: 'world' }, + { c: { e: 'foo' }, d: 'bar' }, + ], + }, + }; + const path = 'a.b[0].c.e'; + const actual = getContextualRowData( + { + type: 'textfield', + input: true, + key: 'c.e', + }, + path, + data, + ); + const expected = { c: { e: 'zed' }, d: 'world' }; + expect(actual).to.deep.equal(expected); + }); + }); + + describe('eachComponentDataAsync', function () { + it('Should iterate over each component and data given a flat components array', async function () { + const components = [ + { + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + { type: 'textarea', - wysiwyg: true, + key: 'textArea', + label: 'Text Area', input: true, + }, + ]; + const data = { + textField: 'hello', + textArea: 'world', + }; + const rowResults: Map = new Map(); + await eachComponentDataAsync(components, data, async (component, data, row, path) => { + const value = get(data, path); + rowResults.set(path, [component, value]); + }); + expect(rowResults.size).to.equal(2); + expect(rowResults.get('textField')).to.deep.equal([ + { + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + 'hello', + ]); + expect(rowResults.get('textArea')).to.deep.equal([ + { + type: 'textarea', key: 'textArea', + label: 'Text Area', + input: true, }, - ], - }; - const data = { - dataGrid: [ + 'world', + ]); + }); + + it('Should iterate over each component and data given a container component and a nested components array', async function () { + const components = [ { - textField: 'hello', - checkbox: true, - textArea: '

world

', - }, - ], - }; - const actual = isComponentDataEmpty(component, data, 'dataGrid'); - const expected = false; - expect(actual).to.equal(expected); - }); + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + { + type: 'container', + key: 'container', + label: 'Container', + input: true, + components: [ + { + type: 'textfield', + key: 'nestedTextField', + label: 'Nested Text Field', + input: true, + }, + { + type: 'textarea', + key: 'nestedTextArea', + label: 'Nested Text Area', + input: true, + }, + ], + }, + ]; + const data = { + textField: 'hello', + container: { + nestedTextField: 'world', + nestedTextArea: 'foo', + }, + }; + const rowResults: Map = new Map(); + await eachComponentDataAsync(components, data, async (component, data, row, path) => { + const value = get(data, path); + rowResults.set(path, [component, value]); + }); + expect(rowResults.size).to.equal(4); + expect(rowResults.get('textField')).to.deep.equal([ + { + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + 'hello', + ]); + expect(rowResults.get('container')).to.deep.equal([ + { + type: 'container', + key: 'container', + label: 'Container', + input: true, + components: [ + { + type: 'textfield', + key: 'nestedTextField', + label: 'Nested Text Field', + input: true, + }, + { + type: 'textarea', + key: 'nestedTextArea', + label: 'Nested Text Area', + input: true, + }, + ], + }, + { + nestedTextField: 'world', + nestedTextArea: 'foo', + }, + ]); + expect(rowResults.get('container.nestedTextField')).to.deep.equal([ + { + type: 'textfield', + key: 'nestedTextField', + label: 'Nested Text Field', + input: true, + }, + 'world', + ]); + expect(rowResults.get('container.nestedTextArea')).to.deep.equal([ + { + type: 'textarea', + key: 'nestedTextArea', + label: 'Nested Text Area', + input: true, + }, + 'foo', + ]); + }); - it('Should return true for an empty Select Boxes component', () => { - const component = { - type: 'selectboxes', - input: true, - key: 'selectBoxes', - data: { - values: [ + it('Should iterate over each component and data given a datagrid component and a nested components array', async function () { + const components = [ + { + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + { + type: 'datagrid', + key: 'dataGrid', + label: 'Data Grid', + input: true, + components: [ + { + type: 'textfield', + key: 'nestedTextField', + label: 'Nested Text Field', + input: true, + }, + { + type: 'textarea', + key: 'nestedTextArea', + label: 'Nested Text Area', + input: true, + }, + ], + }, + ]; + const data = { + textField: 'hello', + dataGrid: [ { - label: 'foo', - value: 'foo', + nestedTextField: 'world', + nestedTextArea: 'foo', }, { - label: 'bar', - value: 'bar', + nestedTextField: 'bar', + nestedTextArea: 'baz', }, ], - }, - }; - const data = { - selectBoxes: {}, - }; - const actual = isComponentDataEmpty(component, data, 'selectBoxes'); - const expected = true; - expect(actual).to.equal(expected); - }); - - it('Should return true for a non-empty Select Boxes component with no selected values', () => { - const component = { - type: 'selectboxes', - input: true, - key: 'selectBoxes', - data: { - values: [ + }; + const rowResults: Map = new Map(); + await eachComponentDataAsync(components, data, async (component, data, row, path) => { + const value = get(data, path); + rowResults.set(path, [component, value]); + }); + expect(rowResults.size).to.equal(6); + expect(rowResults.get('textField')).to.deep.equal([ + { + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + 'hello', + ]); + expect(rowResults.get('dataGrid')).to.deep.equal([ + { + type: 'datagrid', + key: 'dataGrid', + label: 'Data Grid', + input: true, + components: [ + { + type: 'textfield', + key: 'nestedTextField', + label: 'Nested Text Field', + input: true, + }, + { + type: 'textarea', + key: 'nestedTextArea', + label: 'Nested Text Area', + input: true, + }, + ], + }, + [ { - label: 'foo', - value: 'foo', + nestedTextField: 'world', + nestedTextArea: 'foo', }, { - label: 'bar', - value: 'bar', + nestedTextField: 'bar', + nestedTextArea: 'baz', }, ], - }, - }; - const data = { - selectBoxes: { - foo: false, - bar: false, - }, - }; - const actual = isComponentDataEmpty(component, data, 'selectBoxes'); - const expected = true; - expect(actual).to.equal(expected); - }); + ]); + expect(rowResults.get('dataGrid[0].nestedTextField')).to.deep.equal([ + { + type: 'textfield', + key: 'nestedTextField', + label: 'Nested Text Field', + input: true, + }, + 'world', + ]); + }); - it('Should return false for a non-empty Select Boxes component with selected values', () => { - const component = { - type: 'selectboxes', - input: true, - key: 'selectBoxes', - data: { - values: [ + it('Should iterate over a components array and include components that are not in the data object if the includeAll flag is set to true', async function () { + const components = [ + { + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + { + type: 'textarea', + key: 'textArea', + label: 'Text Area', + input: true, + }, + ]; + const data = { + textField: 'hello', + }; + const rowResults: Map = new Map(); + await eachComponentDataAsync( + components, + data, + async (component, data, row, path) => { + const value = get(data, path); + rowResults.set(path, [component, value]); + }, + undefined, + undefined, + undefined, + true, + ); + expect(rowResults.size).to.equal(2); + expect(rowResults.get('textField')).to.deep.equal([ + { + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + 'hello', + ]); + expect(rowResults.get('textArea')).to.deep.equal([ + { + type: 'textarea', + key: 'textArea', + label: 'Text Area', + input: true, + }, + undefined, + ]); + }); + + describe('Flattened form components (for evaluation)', function () { + it('Should return the correct contextual row data for each component', async function () { + const components = [ { - label: 'foo', - value: 'foo', + type: 'textfield', + key: 'textField', + input: true, + tableView: true, }, { - label: 'bar', - value: 'bar', + type: 'datagrid', + key: 'dataGrid', + input: true, + tableView: true, }, - ], - }, - }; - const data = { - selectBoxes: { - foo: true, - bar: false, - }, - }; - const actual = isComponentDataEmpty(component, data, 'selectBoxes'); - const expected = false; - expect(actual).to.equal(expected); - }); + { + type: 'textfield', + key: 'dataGrid[0].nestedTextField', + input: true, + tableView: true, + }, + { + type: 'editgrid', + key: 'dataGrid[0].nestedEditGrid', + input: true, + tableView: true, + }, + { + type: 'textfield', + key: 'dataGrid[0].nestedEditGrid[0].nestedNestedTextField', + input: true, + tableView: true, + }, + ]; + const data = { + textField: 'hello', + dataGrid: [ + { + nestedTextField: 'world', + nestedEditGrid: [ + { + nestedNestedTextField: 'foo', + }, + ], + }, + { + nestedTextField: 'bar', + nestedEditGrid: [ + { + nestedNestedTextField: 'baz', + }, + ], + }, + ], + }; + const rowResults: Map = new Map(); + await eachComponentDataAsync(components, data, async (component, data, row, path) => { + rowResults.set(path, row); + }); + console.log(rowResults); + }); + }); - it('Should return true for an empty Select component', () => { - const component = { - type: 'select', - input: true, - key: 'select', - data: { - values: [ + describe('Normal form components', function () { + it('Should return the correct contextual row data for each component', async function () { + const components = [ { - label: 'foo', - value: 'foo', + type: 'textfield', + key: 'textField', + input: true, + tableView: true, }, { - label: 'bar', - value: 'bar', + type: 'datagrid', + key: 'dataGrid', + input: true, + tableView: true, + components: [ + { + type: 'textfield', + key: 'nestedTextField', + input: true, + tableView: true, + }, + { + type: 'editGrid', + key: 'nestedEditGrid', + input: true, + tableView: true, + components: [ + { + type: 'textfield', + key: 'nestedNestedTextField', + input: true, + tableView: true, + }, + ], + }, + ], }, - ], - }, - }; - const data = { - select: '', - }; - const actual = isComponentDataEmpty(component, data, 'select'); - const expected = true; - expect(actual).to.equal(expected); + ]; + const data = { + textField: 'hello', + dataGrid: [ + { + nestedTextField: 'world', + nestedEditGrid: [ + { + nestedNestedTextField: 'foo', + }, + ], + }, + { + nestedTextField: 'bar', + nestedEditGrid: [ + { + nestedNestedTextField: 'baz', + }, + ], + }, + ], + }; + const rowResults: Map = new Map(); + await eachComponentDataAsync(components, data, async (component, data, row, path) => { + rowResults.set(path, row); + }); + console.log(rowResults); + }); + }); }); - it('Should return true for an empty plain Text Area component', () => { - const component = { - type: 'textarea', - input: true, - key: 'textArea', - }; - const data = { - textArea: '', - }; - const actual = isComponentDataEmpty(component, data, 'textArea'); - const expected = true; - expect(actual).to.equal(expected); - }); + describe('isComponentDataEmpty', function () { + it('Should return true for an empty object', function () { + const component = { + type: 'textfield', + input: true, + key: 'textField', + }; + const data = {}; + const actual = isComponentDataEmpty(component, data, 'textField'); + const expected = true; + expect(actual).to.equal(expected); + }); - it('Should return true for a non-empty non-plain Text Area component with only WYSIWYG or editor HTML', () => { - const component = { - type: 'textarea', - input: true, - key: 'textArea', - wysiwyg: true, - }; - const data = { - textArea: '

 

', - }; - const actual = isComponentDataEmpty(component, data, 'textArea'); - const expected = true; - expect(actual).to.equal(expected); - }); + it('Should return false for a non-empty object', function () { + const component = { + type: 'textfield', + input: true, + key: 'textField', + }; + const data = { + textField: 'hello', + }; + const actual = isComponentDataEmpty(component, data, 'textField'); + const expected = false; + expect(actual).to.equal(expected); + }); - it('Should return true for a non-empty text area with only whitespace', () => { - const component = { - type: 'textarea', - input: true, - key: 'textArea', - }; - const data = { - textArea: ' ', - }; - const actual = isComponentDataEmpty(component, data, 'textArea'); - const expected = true; - expect(actual).to.equal(expected); - }); + it('Should return true for a checkbox component set to false', function () { + const component = { + type: 'checkbox', + input: true, + key: 'checkbox', + }; + const data = { + checkbox: false, + }; + const actual = isComponentDataEmpty(component, data, 'checkbox'); + const expected = true; + expect(actual).to.equal(expected); + }); - it('Should return false for a non-empty Text Field', () => { - const component = { - type: 'textfield', - input: true, - key: 'textField', - }; - const data = { - textField: 'hello', - }; - const actual = isComponentDataEmpty(component, data, 'textField'); - const expected = false; - expect(actual).to.equal(expected); - }); + it('Should return false for a checkbox component set to true', function () { + const component = { + type: 'checkbox', + input: true, + key: 'checkbox', + }; + const data = { + checkbox: true, + }; + const actual = isComponentDataEmpty(component, data, 'checkbox'); + const expected = false; + expect(actual).to.equal(expected); + }); + + it('Should return true for an empty dataGrid component', function () { + const component = { + type: 'datagrid', + input: true, + key: 'dataGrid', + }; + const data = { + dataGrid: [], + }; + const actual = isComponentDataEmpty(component, data, 'dataGrid'); + const expected = true; + expect(actual).to.equal(expected); + }); + + it('Should return true for a non-empty dataGrid component with empty child components', function () { + const component = { + type: 'datagrid', + input: true, + key: 'dataGrid', + components: [ + { + type: 'textfield', + input: true, + key: 'textField', + }, + { + type: 'checkbox', + input: true, + key: 'checkbox', + }, + { + type: 'textarea', + wysiwyg: true, + input: true, + key: 'textArea', + }, + ], + }; + const data = { + dataGrid: [ + { + textField: '', + checkbox: false, + textArea: '

 

', + }, + ], + }; + const actual = isComponentDataEmpty(component, data, 'dataGrid'); + const expected = true; + expect(actual).to.equal(expected); + }); + + it('Should return false for a datagrid with non-empty child components', function () { + const component = { + type: 'datagrid', + input: true, + key: 'dataGrid', + components: [ + { + type: 'textfield', + input: true, + key: 'textField', + }, + { + type: 'checkbox', + input: true, + key: 'checkbox', + }, + { + type: 'textarea', + wysiwyg: true, + input: true, + key: 'textArea', + }, + ], + }; + const data = { + dataGrid: [ + { + textField: 'hello', + checkbox: true, + textArea: '

world

', + }, + ], + }; + const actual = isComponentDataEmpty(component, data, 'dataGrid'); + const expected = false; + expect(actual).to.equal(expected); + }); + + it('Should return true for an empty Select Boxes component', function () { + const component = { + type: 'selectboxes', + input: true, + key: 'selectBoxes', + data: { + values: [ + { + label: 'foo', + value: 'foo', + }, + { + label: 'bar', + value: 'bar', + }, + ], + }, + }; + const data = { + selectBoxes: {}, + }; + const actual = isComponentDataEmpty(component, data, 'selectBoxes'); + const expected = true; + expect(actual).to.equal(expected); + }); + + it('Should return true for a non-empty Select Boxes component with no selected values', function () { + const component = { + type: 'selectboxes', + input: true, + key: 'selectBoxes', + data: { + values: [ + { + label: 'foo', + value: 'foo', + }, + { + label: 'bar', + value: 'bar', + }, + ], + }, + }; + const data = { + selectBoxes: { + foo: false, + bar: false, + }, + }; + const actual = isComponentDataEmpty(component, data, 'selectBoxes'); + const expected = true; + expect(actual).to.equal(expected); + }); - it('Should return true for an empty Text Field component', () => { - const component = { - type: 'textfield', - input: true, - key: 'textField', - }; - const data = { - textField: '', - }; - const actual = isComponentDataEmpty(component, data, 'textField'); - const expected = true; - expect(actual).to.equal(expected); - }); + it('Should return false for a non-empty Select Boxes component with selected values', function () { + const component = { + type: 'selectboxes', + input: true, + key: 'selectBoxes', + data: { + values: [ + { + label: 'foo', + value: 'foo', + }, + { + label: 'bar', + value: 'bar', + }, + ], + }, + }; + const data = { + selectBoxes: { + foo: true, + bar: false, + }, + }; + const actual = isComponentDataEmpty(component, data, 'selectBoxes'); + const expected = false; + expect(actual).to.equal(expected); + }); - it('Should return true for a non-empty Text Field component with only whitespace', () => { - const component = { - type: 'textfield', - input: true, - key: 'textField', - }; - const data = { - textField: ' ', - }; - const actual = isComponentDataEmpty(component, data, 'textField'); - const expected = true; - expect(actual).to.equal(expected); - }); -}); + it('Should return true for an empty Select component', function () { + const component = { + type: 'select', + input: true, + key: 'select', + data: { + values: [ + { + label: 'foo', + value: 'foo', + }, + { + label: 'bar', + value: 'bar', + }, + ], + }, + }; + const data = { + select: '', + }; + const actual = isComponentDataEmpty(component, data, 'select'); + const expected = true; + expect(actual).to.equal(expected); + }); -describe('eachComponent', () => { - it('Should iterate over each component given a flat components array', () => { - const components = [ - { - type: 'textfield', - key: 'textField', + it('Should return true for an empty plain Text Area component', function () { + const component = { + type: 'textarea', input: true, - }, - { + key: 'textArea', + }; + const data = { + textArea: '', + }; + const actual = isComponentDataEmpty(component, data, 'textArea'); + const expected = true; + expect(actual).to.equal(expected); + }); + + it('Should return true for a non-empty non-plain Text Area component with only WYSIWYG or editor HTML', function () { + const component = { type: 'textarea', + input: true, key: 'textArea', + wysiwyg: true, + }; + const data = { + textArea: '

 

', + }; + const actual = isComponentDataEmpty(component, data, 'textArea'); + const expected = true; + expect(actual).to.equal(expected); + }); + + it('Should return true for a non-empty text area with only whitespace', function () { + const component = { + type: '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, + key: 'textArea', + }; + const data = { + textArea: ' ', + }; + const actual = isComponentDataEmpty(component, data, 'textArea'); + const expected = true; + expect(actual).to.equal(expected); }); - }); - it('Should iterate over each component with correct pathing given a container component', () => { - const components = [ - { + it('Should return false for a non-empty Text Field', function () { + const component = { type: 'textfield', + input: true, key: 'textField', + }; + const data = { + textField: 'hello', + }; + const actual = isComponentDataEmpty(component, data, 'textField'); + const expected = false; + expect(actual).to.equal(expected); + }); + + it('Should return true for an empty Text Field component', function () { + const component = { + type: 'textfield', input: true, - }, - { - type: 'container', - key: 'container', + key: 'textField', + }; + const data = { + textField: '', + }; + const actual = isComponentDataEmpty(component, data, 'textField'); + const expected = true; + expect(actual).to.equal(expected); + }); + + it('Should return true for a non-empty Text Field component with only whitespace', function () { + const component = { + type: 'textfield', 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: [ + key: 'textField', + }; + const data = { + textField: ' ', + }; + const actual = isComponentDataEmpty(component, data, 'textField'); + const expected = true; + expect(actual).to.equal(expected); + }); + }); + + describe('eachComponentData', function () { + it('Should iterate over each component and data given a flat components array', function () { + const components = [ + { + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + { + type: 'textarea', + key: 'textArea', + label: 'Text Area', + input: true, + }, + ]; + const data = { + textField: 'hello', + textArea: 'world', + }; + const rowResults: Map = new Map(); + eachComponentData(components, data, (component, data, row, path) => { + const value = get(data, path); + rowResults.set(path, [component, value]); + }); + expect(rowResults.size).to.equal(2); + expect(rowResults.get('textField')).to.deep.equal([ + { + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + 'hello', + ]); + expect(rowResults.get('textArea')).to.deep.equal([ + { + type: 'textarea', + key: 'textArea', + label: 'Text Area', + input: true, + }, + 'world', + ]); + }); + + it('Should iterate over each component and data given a container component and a nested components array', function () { + const components = [ + { + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + { + type: 'container', + key: 'container', + label: 'Container', + input: true, + components: [ + { + type: 'textfield', + key: 'nestedTextField', + label: 'Nested Text Field', + input: true, + }, + { + type: 'textarea', + key: 'nestedTextArea', + label: 'Nested Text Area', + input: true, + }, + ], + }, + ]; + const data = { + textField: 'hello', + container: { + nestedTextField: 'world', + nestedTextArea: 'foo', + }, + }; + const rowResults: Map = new Map(); + eachComponentData(components, data, (component, data, row, path) => { + const value = get(data, path); + rowResults.set(path, [component, value]); + }); + expect(rowResults.size).to.equal(4); + expect(rowResults.get('textField')).to.deep.equal([ + { + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + 'hello', + ]); + expect(rowResults.get('container')).to.deep.equal([ + { + type: 'container', + key: 'container', + label: 'Container', + input: true, + components: [ + { + type: 'textfield', + key: 'nestedTextField', + label: 'Nested Text Field', + input: true, + }, + { + type: 'textarea', + key: 'nestedTextArea', + label: 'Nested Text Area', + input: true, + }, + ], + }, + { + nestedTextField: 'world', + nestedTextArea: 'foo', + }, + ]); + expect(rowResults.get('container.nestedTextField')).to.deep.equal([ { type: 'textfield', key: 'nestedTextField', + label: 'Nested Text Field', input: true, }, + 'world', + ]); + expect(rowResults.get('container.nestedTextArea')).to.deep.equal([ { type: 'textarea', key: 'nestedTextArea', + label: 'Nested Text Area', input: true, }, - ], + 'foo', + ]); }); - 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', () => { - const components = [ - { - type: 'textfield', - key: 'textField', - input: true, - }, - { - type: 'datagrid', - key: 'dataGrid', - input: true, - components: [ + it('Should iterate over each component and data given a datagrid component and a nested components array', function () { + const components = [ + { + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + { + type: 'datagrid', + key: 'dataGrid', + label: 'Data Grid', + input: true, + components: [ + { + type: 'textfield', + key: 'nestedTextField', + label: 'Nested Text Field', + input: true, + }, + { + type: 'textarea', + key: 'nestedTextArea', + label: 'Nested Text Area', + input: true, + }, + ], + }, + ]; + const data = { + textField: 'hello', + dataGrid: [ { - type: 'textfield', - key: 'nestedTextField', - input: true, + nestedTextField: 'world', + nestedTextArea: 'foo', }, { - type: 'textarea', - key: 'nestedTextArea', - input: true, + nestedTextField: 'bar', + nestedTextArea: 'baz', }, ], - }, - ]; - 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: [ + }; + const rowResults: Map = new Map(); + eachComponentData(components, data, (component, data, row, path) => { + const value = get(data, path); + rowResults.set(path, [component, value]); + }); + expect(rowResults.size).to.equal(6); + expect(rowResults.get('textField')).to.deep.equal([ + { + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + 'hello', + ]); + expect(rowResults.get('dataGrid')).to.deep.equal([ + { + type: 'datagrid', + key: 'dataGrid', + label: 'Data Grid', + input: true, + components: [ + { + type: 'textfield', + key: 'nestedTextField', + label: 'Nested Text Field', + input: true, + }, + { + type: 'textarea', + key: 'nestedTextArea', + label: 'Nested Text Area', + input: true, + }, + ], + }, + [ + { + nestedTextField: 'world', + nestedTextArea: 'foo', + }, + { + nestedTextField: 'bar', + nestedTextArea: 'baz', + }, + ], + ]); + expect(rowResults.get('dataGrid[0].nestedTextField')).to.deep.equal([ + { + type: 'textfield', + key: 'nestedTextField', + label: 'Nested Text Field', + input: true, + }, + 'world', + ]); + }); + + it('Should iterate over a components array and include components that are not in the data object if the includeAll flag is set to true', function () { + const components = [ { type: 'textfield', - key: 'nestedTextField', + key: 'textField', + label: 'Text Field', input: true, }, { type: 'textarea', - key: 'nestedTextArea', + key: 'textArea', + label: 'Text Area', 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, + ]; + const data = { + textField: 'hello', + }; + const rowResults: Map = new Map(); + eachComponentData( + components, + data, + (component, data, row, path) => { + const value = get(data, path); + rowResults.set(path, [component, value]); + }, + undefined, + undefined, + undefined, + true, + ); + expect(rowResults.size).to.equal(2); + expect(rowResults.get('textField')).to.deep.equal([ + { + type: 'textfield', + key: 'textField', + label: 'Text Field', + input: true, + }, + 'hello', + ]); + expect(rowResults.get('textArea')).to.deep.equal([ + { + type: 'textarea', + key: 'textArea', + label: 'Text Area', + input: true, + }, + undefined, + ]); }); }); - it("Should iterate over each component with correct pathing given a datagrid's child components", () => { - const components = [ - { - type: 'datagrid', - key: 'dataGrid', + describe('getComponentActualValue', function () { + it('Should return correct value for component inside inside panel inside editGrid', function () { + const component = { + label: 'Radio', + optionsLabelPosition: 'right', + inline: false, + tableView: false, + values: [ + { label: 'yes', value: 'yes', shortcut: '' }, + { label: 'no', value: 'no', shortcut: '' }, + ], + key: 'radio', + type: 'radio', input: true, - components: [ - { - type: 'textfield', - key: 'nestedTextField', - input: true, - }, - { - type: 'textarea', - key: 'nestedTextArea', + path: 'editGrid.radio', + parent: { + collapsible: false, + key: 'panel', + type: 'panel', + label: 'Panel', + input: false, + tableView: false, + path: 'editGrid[0].panel', + parent: { + label: 'Edit Grid', + tableView: false, + rowDrafts: false, + key: 'editGrid', + type: 'editgrid', + path: 'editGrid', + displayAsTable: false, 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, + }, + }; + const compPath = 'editGrid.radio'; + const data = { + editGrid: [{ radio: 'yes', textArea: 'test' }], + submit: true, + }; + const row = { radio: 'yes', textArea: 'test' }; + + const value = getComponentActualValue(component, compPath, data, row); + expect(value).to.equal('yes'); }); }); -}); -describe('eachComponentData', () => { - it('Should iterate over each component and data given a flat components array', () => { - const components = [ - { - type: 'textfield', - key: 'textField', + describe('hasCondition', function () { + it('Should return false if conditions is saved in invalid state', function () { + const component = { label: 'Text Field', - input: true, - }, - { - type: 'textarea', - key: 'textArea', - label: 'Text Area', - input: true, - }, - ]; - const data = { - textField: 'hello', - textArea: 'world', - }; - const rowResults: Map = new Map(); - eachComponentData(components, data, (component, data, row, path) => { - const value = get(data, path); - rowResults.set(path, [component, value]); - }); - expect(rowResults.size).to.equal(2); - expect(rowResults.get('textField')).to.deep.equal([ - { - type: 'textfield', + hidden: true, key: 'textField', - label: 'Text Field', + conditional: { + conjunction: 'all', + }, + type: 'textfield', input: true, - }, - 'hello', - ]); - expect(rowResults.get('textArea')).to.deep.equal([ - { + }; + + const result = hasCondition(component as Component); + expect(result).to.equal(false); + }); + }); + + describe('getModelType', function () { + it('Should return the correct model type for taxtarea with JSON data type', function () { + const component = { type: 'textarea', - key: 'textArea', - label: 'Text Area', input: true, - }, - 'world', - ]); - }); + key: 'textField', + editor: 'ace', + as: 'json', + }; + const actual = getModelType(component); + const expected = 'any'; + expect(actual).to.equal(expected); + }); - it('Should iterate over each component and data given a container component and a nested components array', () => { - const components = [ - { + it('Should return the correct model type for a component', function () { + const component = { type: 'textfield', - key: 'textField', - label: 'Text Field', - input: true, - }, - { - type: 'container', - key: 'container', - label: 'Container', input: true, - components: [ - { - type: 'textfield', - key: 'nestedTextField', - label: 'Nested Text Field', - input: true, - }, - { - type: 'textarea', - key: 'nestedTextArea', - label: 'Nested Text Area', - input: true, - }, - ], - }, - ]; - const data = { - textField: 'hello', - container: { - nestedTextField: 'world', - nestedTextArea: 'foo', - }, - }; - const rowResults: Map = new Map(); - eachComponentData(components, data, (component, data, row, path) => { - const value = get(data, path); - rowResults.set(path, [component, value]); - }); - expect(rowResults.size).to.equal(4); - expect(rowResults.get('textField')).to.deep.equal([ - { - type: 'textfield', key: 'textField', - label: 'Text Field', - input: true, - }, - 'hello', - ]); - expect(rowResults.get('container')).to.deep.equal([ - { - type: 'container', - key: 'container', - label: 'Container', + }; + const actual = getModelType(component); + const expected = 'string'; + expect(actual).to.equal(expected); + }); + + it('Should return the correct model type for a component with a number input type', function () { + const component = { + type: 'number', input: true, - components: [ - { - type: 'textfield', - key: 'nestedTextField', - label: 'Nested Text Field', - input: true, - }, - { - type: 'textarea', - key: 'nestedTextArea', - label: 'Nested Text Area', - input: true, - }, - ], - }, - { - nestedTextField: 'world', - nestedTextArea: 'foo', - }, - ]); - expect(rowResults.get('container.nestedTextField')).to.deep.equal([ - { - type: 'textfield', - key: 'nestedTextField', - label: 'Nested Text Field', + key: 'number', + }; + const actual = getModelType(component); + const expected = 'number'; + expect(actual).to.equal(expected); + }); + + it('Should return the correct model type for a component with a boolean input type', function () { + const component = { + type: 'checkbox', input: true, - }, - 'world', - ]); - expect(rowResults.get('container.nestedTextArea')).to.deep.equal([ - { - type: 'textarea', - key: 'nestedTextArea', - label: 'Nested Text Area', + key: 'checkbox', + }; + const actual = getModelType(component); + const expected = 'boolean'; + expect(actual).to.equal(expected); + }); + + it('Should return the correct model type for a component with a datetime input type', function () { + const component = { + type: 'datetime', input: true, - }, - 'foo', - ]); - }); + key: 'datetime', + }; + const actual = getModelType(component); + const expected = 'string'; + expect(actual).to.equal(expected); + }); - it('Should iterate over each component and data given a datagrid component and a nested components array', () => { - const components = [ - { - type: 'textfield', - key: 'textField', - label: 'Text Field', + it('Should return the correct model type for a component with a date input type', function () { + const component = { + type: 'datetime', input: true, - }, - { - type: 'datagrid', - key: 'dataGrid', - label: 'Data Grid', + key: 'date', + format: 'yyyy-MM-dd', + }; + const actual = getModelType(component); + const expected = 'string'; + expect(actual).to.equal(expected); + }); + + it('Should return the correct model type for a component with a time input type', function () { + const component = { + type: 'datetime', input: true, - components: [ - { - type: 'textfield', - key: 'nestedTextField', - label: 'Nested Text Field', - input: true, - }, - { - type: 'textarea', - key: 'nestedTextArea', - label: 'Nested Text Area', - input: true, - }, - ], - }, - ]; - const data = { - textField: 'hello', - dataGrid: [ - { - nestedTextField: 'world', - nestedTextArea: 'foo', - }, - { - nestedTextField: 'bar', - nestedTextArea: 'baz', - }, - ], - }; - const rowResults: Map = new Map(); - eachComponentData(components, data, (component, data, row, path) => { - const value = get(data, path); - rowResults.set(path, [component, value]); - }); - expect(rowResults.size).to.equal(6); - expect(rowResults.get('textField')).to.deep.equal([ - { - type: 'textfield', - key: 'textField', - label: 'Text Field', + key: 'time', + format: 'HH:mm:ss', + }; + const actual = getModelType(component); + const expected = 'string'; + expect(actual).to.equal(expected); + }); + + it('Should return the correct model type for a component with a currency input type', function () { + const component = { + type: 'currency', input: true, - }, - 'hello', - ]); - expect(rowResults.get('dataGrid')).to.deep.equal([ - { - type: 'datagrid', - key: 'dataGrid', - label: 'Data Grid', + key: 'currency', + }; + const actual = getModelType(component); + const expected = 'number'; + expect(actual).to.equal(expected); + }); + + it('Should return the correct model type for a component with a email input type', function () { + const component = { + type: 'email', input: true, - components: [ - { - type: 'textfield', - key: 'nestedTextField', - label: 'Nested Text Field', - input: true, - }, - { - type: 'textarea', - key: 'nestedTextArea', - label: 'Nested Text Area', - input: true, - }, - ], - }, - [ - { - nestedTextField: 'world', - nestedTextArea: 'foo', - }, - { - nestedTextField: 'bar', - nestedTextArea: 'baz', - }, - ], - ]); - expect(rowResults.get('dataGrid[0].nestedTextField')).to.deep.equal([ - { - type: 'textfield', - key: 'nestedTextField', - label: 'Nested Text Field', + key: 'email', + }; + const actual = getModelType(component); + const expected = 'string'; + expect(actual).to.equal(expected); + }); + + it('Should return the correct model type for a component with a phoneNumber input type', function () { + const component = { + type: 'phoneNumber', input: true, - }, - 'world', - ]); - }); + key: 'phoneNumber', + }; + const actual = getModelType(component); + const expected = 'string'; + expect(actual).to.equal(expected); + }); - it('Should iterate over a components array and include components that are not in the data object if the includeAll flag is set to true', () => { - const components = [ - { - type: 'textfield', - key: 'textField', - label: 'Text Field', + it('Should return the correct model type for a component with a url input type', function () { + const component = { + type: 'url', input: true, - }, - { + key: 'url', + }; + const actual = getModelType(component); + const expected = 'string'; + expect(actual).to.equal(expected); + }); + + it('Should return the correct model type for a component with a textarea input type', function () { + const component = { type: 'textarea', - key: 'textArea', - label: 'Text Area', - input: true, - }, - ]; - const data = { - textField: 'hello', - }; - const rowResults: Map = new Map(); - eachComponentData( - components, - data, - (component, data, row, path) => { - const value = get(data, path); - rowResults.set(path, [component, value]); - }, - undefined, - undefined, - undefined, - true - ); - expect(rowResults.size).to.equal(2); - expect(rowResults.get('textField')).to.deep.equal([ - { - type: 'textfield', - key: 'textField', - label: 'Text Field', input: true, - }, - 'hello', - ]); - expect(rowResults.get('textArea')).to.deep.equal([ - { - type: 'textarea', - key: 'textArea', - label: 'Text Area', + key: 'textarea', + }; + const actual = getModelType(component); + const expected = 'any'; + expect(actual).to.equal(expected); + }); + + it('Should return the correct model type for a component with a signature input type', function () { + const component = { + type: 'signature', input: true, - }, - undefined, - ]); - }); -}); + key: 'signature', + }; + const actual = getModelType(component); + const expected = 'string'; + expect(actual).to.equal(expected); + }); -describe('getComponentActualValue', () => { - it('Should return correct value for component inside inside panel inside editGrid', () => { - const component = { - label: 'Radio', - optionsLabelPosition: 'right', - inline: false, - tableView: false, - values: [ - { label: 'yes', value: 'yes', shortcut: '' }, - { label: 'no', value: 'no', shortcut: '' }, - ], - key: 'radio', - type: 'radio', - input: true, - path: 'editGrid.radio', - parent: { - collapsible: false, - key: 'panel', - type: 'panel', - label: 'Panel', - input: false, - tableView: false, - path: 'editGrid[0].panel', - parent: { - label: 'Edit Grid', - tableView: false, - rowDrafts: false, - key: 'editGrid', - type: 'editgrid', - path: 'editGrid', - displayAsTable: false, - input: true, + it('Should return the correct model type for a component with a select input type', function () { + const component = { + type: 'select', + input: true, + key: 'select', + data: { + values: [ + { label: 'foo', value: 'foo' }, + { label: 'bar', value: 'bar' }, + ], }, - }, - }; - const compPath = 'editGrid.radio'; - const data = { - editGrid: [{ radio: 'yes', textArea: 'test' }], - submit: true, - }; - const row = { radio: 'yes', textArea: 'test' }; - - const value = getComponentActualValue(component, compPath, data, row); - expect(value).to.equal('yes'); - }); -}); - -describe('hasCondition', () => { - it('Should return false if conditions is saved in invalid state', () => { - const component = { - label: 'Text Field', - hidden: true, - key: 'textField', - conditional: { - conjunction: 'all', - }, - type: 'textfield', - input: true, - }; - - const result = hasCondition(component as Component); - expect(result).to.equal(false); - }); -}); - -describe('getModelType', () => { - it('Should return the correct model type for taxtarea with JSON data type', () => { - const component = { - type: 'textarea', - input: true, - key: 'textField', - editor: 'ace', - as: 'json', - }; - const actual = getModelType(component); - const expected = 'any'; - expect(actual).to.equal(expected); - }); - - it('Should return the correct model type for a component', () => { - const component = { - type: 'textfield', - input: true, - key: 'textField', - }; - const actual = getModelType(component); - const expected = 'string'; - expect(actual).to.equal(expected); - }); - - it('Should return the correct model type for a component with a number input type', () => { - const component = { - type: 'number', - input: true, - key: 'number', - }; - const actual = getModelType(component); - const expected = 'number'; - expect(actual).to.equal(expected); - }); - - it('Should return the correct model type for a component with a boolean input type', () => { - const component = { - type: 'checkbox', - input: true, - key: 'checkbox', - }; - const actual = getModelType(component); - const expected = 'boolean'; - expect(actual).to.equal(expected); - }); - - it('Should return the correct model type for a component with a datetime input type', () => { - const component = { - type: 'datetime', - input: true, - key: 'datetime', - }; - const actual = getModelType(component); - const expected = 'string'; - expect(actual).to.equal(expected); - }); - - it('Should return the correct model type for a component with a date input type', () => { - const component = { - type: 'datetime', - input: true, - key: 'date', - format: 'yyyy-MM-dd', - }; - const actual = getModelType(component); - const expected = 'string'; - expect(actual).to.equal(expected); - }); - - it('Should return the correct model type for a component with a time input type', () => { - const component = { - type: 'datetime', - input: true, - key: 'time', - format: 'HH:mm:ss', - }; - const actual = getModelType(component); - const expected = 'string'; - expect(actual).to.equal(expected); - }); - - it('Should return the correct model type for a component with a currency input type', () => { - const component = { - type: 'currency', - input: true, - key: 'currency', - }; - const actual = getModelType(component); - const expected = 'number'; - expect(actual).to.equal(expected); - }); - - it('Should return the correct model type for a component with a email input type', () => { - const component = { - type: 'email', - input: true, - key: 'email', - }; - const actual = getModelType(component); - const expected = 'string'; - expect(actual).to.equal(expected); - }); - - it('Should return the correct model type for a component with a phoneNumber input type', () => { - const component = { - type: 'phoneNumber', - input: true, - key: 'phoneNumber', - }; - const actual = getModelType(component); - const expected = 'string'; - expect(actual).to.equal(expected); - }); - - it('Should return the correct model type for a component with a url input type', () => { - const component = { - type: 'url', - input: true, - key: 'url', - }; - const actual = getModelType(component); - const expected = 'string'; - expect(actual).to.equal(expected); - }); - - it('Should return the correct model type for a component with a textarea input type', () => { - const component = { - type: 'textarea', - input: true, - key: 'textarea', - }; - const actual = getModelType(component); - const expected = 'any'; - expect(actual).to.equal(expected); - }); - - it('Should return the correct model type for a component with a signature input type', () => { - const component = { - type: 'signature', - input: true, - key: 'signature', - }; - const actual = getModelType(component); - const expected = 'string'; - expect(actual).to.equal(expected); - }); - - it('Should return the correct model type for a component with a select input type', () => { - const component = { - type: 'select', - input: true, - key: 'select', - data: { - values: [ - { label: 'foo', value: 'foo' }, - { label: 'bar', value: 'bar' }, - ], - }, - }; - const actual = getModelType(component); - const expected = 'any'; - expect(actual).to.equal(expected); - }); + }; + const actual = getModelType(component); + const expected = 'any'; + expect(actual).to.equal(expected); + }); - it('Should return the correct model type for a component with a selectboxes input type', () => { - const component = { - type: 'selectboxes', - input: true, - key: 'selectboxes', - data: { - values: [ - { label: 'foo', value: 'foo' }, - { label: 'bar', value: 'bar' }, - ], - }, - }; - const actual = getModelType(component); - const expected = 'any'; - expect(actual).to.equal(expected); + it('Should return the correct model type for a component with a selectboxes input type', function () { + const component = { + type: 'selectboxes', + input: true, + key: 'selectboxes', + data: { + values: [ + { label: 'foo', value: 'foo' }, + { label: 'bar', value: 'bar' }, + ], + }, + }; + const actual = getModelType(component); + const expected = 'any'; + expect(actual).to.equal(expected); + }); }); }); diff --git a/src/utils/__tests__/jwtDecode.test.ts b/src/utils/__tests__/jwtDecode.test.ts index 39f449e7..b9ae0aba 100644 --- a/src/utils/__tests__/jwtDecode.test.ts +++ b/src/utils/__tests__/jwtDecode.test.ts @@ -1,113 +1,113 @@ // copied from https://github.com/auth0/jwt-decode const token = - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIiLCJleHAiOjEzOTMyODY4OTMsImlhdCI6MTM5MzI2ODg5M30.4-iaDojEVl0pJQMjrbM1EzUIfAZgsbK_kgnVyVxFSVo'; + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIiLCJleHAiOjEzOTMyODY4OTMsImlhdCI6MTM5MzI2ODg5M30.4-iaDojEVl0pJQMjrbM1EzUIfAZgsbK_kgnVyVxFSVo'; import { jwtDecode } from '../jwtDecode'; import { expect } from 'chai'; describe('Test jwtDecode', function () { - it('should fail to construct without a clientID', function () { - const decoded = jwtDecode(token); - expect(decoded.exp).to.equal(1393286893); - expect(decoded.iat).to.equal(1393268893); - expect(decoded.foo).to.equal('bar'); - }); - - it('should return header information', function () { - const decoded = jwtDecode(token, { header: true }); - expect(decoded.typ).to.equal('JWT'); - expect(decoded.alg).to.equal('HS256'); - }); - - it('should work with utf8 tokens', function () { - const utf8_token = - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiSm9zw6kiLCJpYXQiOjE0MjU2NDQ5NjZ9.1CfFtdGUPs6q8kT3OGQSVlhEMdbuX0HfNSqum0023a0'; - const decoded = jwtDecode(utf8_token); - expect(decoded.name).to.equal('José'); - }); - - it('should work with binary tokens', function () { - const binary_token = - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiSm9z6SIsImlhdCI6MTQyNTY0NDk2Nn0.cpnplCBxiw7Xqz5thkqs4Mo_dymvztnI0CI4BN0d1t8'; - const decoded = jwtDecode(binary_token); - expect(decoded.name).to.equal('José'); - }); - - it('should work with double padding', function () { - const utf8_token = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpvc8OpIiwiaWF0IjoxNTE2MjM5MDIyfQ.7A3F5SUH2gbBSYVon5mas_Y-KCrWojorKQg7UKGVEIA'; - const decoded = jwtDecode(utf8_token); - expect(decoded.name).to.equal('José'); - }); - - it('should work with single padding', function () { - const utf8_token = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpvc8OpZSIsImlhdCI6MTUxNjIzOTAyMn0.tbjJzDAylkKSV0_YGR5xBJBlFK01C82nZPLIcA3JX1g'; - const decoded = jwtDecode(utf8_token); - expect(decoded.name).to.equal('Josée'); - }); - - it('should throw error on nonstring', function () { - const bad_token = null; - expect(function () { - jwtDecode(bad_token as any); - }).to.throw(); - }); - - it('should throw error on string that is not a token', function () { - const bad_token = 'fubar'; - expect(function () { - jwtDecode(bad_token); - }).to.throw(); - }); - - it('should throw InvalidTokenErrors when token is null', function () { - const bad_token = null; - expect(function () { - jwtDecode(bad_token as any, { header: true }); - }).to.throw('Invalid token specified: must be a string'); - }); - - it('should throw error when missing part #1', function () { - const bad_token = '.FAKE_TOKEN'; - expect(function () { - jwtDecode(bad_token, { header: true }); - }).to.throw('Invalid token specified: invalid json for part #1'); - }); - - it('should throw error when part #1 is not valid base64', function () { - const bad_token = 'TOKEN'; - expect(function () { - jwtDecode(bad_token, { header: true }); - }).to.throw('Invalid token specified: invalid base64 for part #1'); - }); - - it('should throw error when part #1 is not valid JSON', function () { - const bad_token = 'FAKE.TOKEN'; - expect(function () { - jwtDecode(bad_token, { header: true }); - }).to.throw('Invalid token specified: invalid json for part #1'); - }); - - it('should throw error when missing part #2', function () { - const bad_token = 'FAKE_TOKEN'; - expect(function () { - jwtDecode(bad_token); - }).to.throw('Invalid token specified: missing part #2'); - }); - - it('should throw error when part #2 is not valid base64', function () { - const bad_token = 'FAKE.TOKEN'; - expect(function () { - jwtDecode(bad_token); - }).to.throw('Invalid token specified: invalid base64 for part #2'); - }); - - it('should throw error when part #2 is not valid JSON', function () { - const bad_token = 'FAKE.TOKEN2'; - expect(function () { - jwtDecode(bad_token); - }).to.throw('Invalid token specified: invalid json for part #2'); - }); + it('should fail to construct without a clientID', function () { + const decoded = jwtDecode(token); + expect(decoded.exp).to.equal(1393286893); + expect(decoded.iat).to.equal(1393268893); + expect(decoded.foo).to.equal('bar'); + }); + + it('should return header information', function () { + const decoded = jwtDecode(token, { header: true }); + expect(decoded.typ).to.equal('JWT'); + expect(decoded.alg).to.equal('HS256'); + }); + + it('should work with utf8 tokens', function () { + const utf8_token = + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiSm9zw6kiLCJpYXQiOjE0MjU2NDQ5NjZ9.1CfFtdGUPs6q8kT3OGQSVlhEMdbuX0HfNSqum0023a0'; + const decoded = jwtDecode(utf8_token); + expect(decoded.name).to.equal('José'); + }); + + it('should work with binary tokens', function () { + const binary_token = + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiSm9z6SIsImlhdCI6MTQyNTY0NDk2Nn0.cpnplCBxiw7Xqz5thkqs4Mo_dymvztnI0CI4BN0d1t8'; + const decoded = jwtDecode(binary_token); + expect(decoded.name).to.equal('José'); + }); + + it('should work with double padding', function () { + const utf8_token = + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpvc8OpIiwiaWF0IjoxNTE2MjM5MDIyfQ.7A3F5SUH2gbBSYVon5mas_Y-KCrWojorKQg7UKGVEIA'; + const decoded = jwtDecode(utf8_token); + expect(decoded.name).to.equal('José'); + }); + + it('should work with single padding', function () { + const utf8_token = + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpvc8OpZSIsImlhdCI6MTUxNjIzOTAyMn0.tbjJzDAylkKSV0_YGR5xBJBlFK01C82nZPLIcA3JX1g'; + const decoded = jwtDecode(utf8_token); + expect(decoded.name).to.equal('Josée'); + }); + + it('should throw error on nonstring', function () { + const bad_token = null; + expect(function () { + jwtDecode(bad_token as any); + }).to.throw(); + }); + + it('should throw error on string that is not a token', function () { + const bad_token = 'fubar'; + expect(function () { + jwtDecode(bad_token); + }).to.throw(); + }); + + it('should throw InvalidTokenErrors when token is null', function () { + const bad_token = null; + expect(function () { + jwtDecode(bad_token as any, { header: true }); + }).to.throw('Invalid token specified: must be a string'); + }); + + it('should throw error when missing part #1', function () { + const bad_token = '.FAKE_TOKEN'; + expect(function () { + jwtDecode(bad_token, { header: true }); + }).to.throw('Invalid token specified: invalid json for part #1'); + }); + + it('should throw error when part #1 is not valid base64', function () { + const bad_token = 'TOKEN'; + expect(function () { + jwtDecode(bad_token, { header: true }); + }).to.throw('Invalid token specified: invalid base64 for part #1'); + }); + + it('should throw error when part #1 is not valid JSON', function () { + const bad_token = 'FAKE.TOKEN'; + expect(function () { + jwtDecode(bad_token, { header: true }); + }).to.throw('Invalid token specified: invalid json for part #1'); + }); + + it('should throw error when missing part #2', function () { + const bad_token = 'FAKE_TOKEN'; + expect(function () { + jwtDecode(bad_token); + }).to.throw('Invalid token specified: missing part #2'); + }); + + it('should throw error when part #2 is not valid base64', function () { + const bad_token = 'FAKE.TOKEN'; + expect(function () { + jwtDecode(bad_token); + }).to.throw('Invalid token specified: invalid base64 for part #2'); + }); + + it('should throw error when part #2 is not valid JSON', function () { + const bad_token = 'FAKE.TOKEN2'; + expect(function () { + jwtDecode(bad_token); + }).to.throw('Invalid token specified: invalid json for part #2'); + }); }); diff --git a/src/utils/__tests__/unwind.test.ts b/src/utils/__tests__/unwind.test.ts index bccbe126..03ea408f 100644 --- a/src/utils/__tests__/unwind.test.ts +++ b/src/utils/__tests__/unwind.test.ts @@ -1,8 +1,8 @@ -const assert = require('assert'); +import assert from 'assert'; import { unwind, rewind } from '../unwind'; -describe('Test Unwinder', () => { - it('Should unwind a form with datagrid and submission data', () => { +describe('Test Unwinder', function () { + it('Should unwind a form with datagrid and submission data', function () { const form = { components: [ { @@ -16,8 +16,8 @@ describe('Test Unwinder', () => { label: 'A', overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', @@ -25,12 +25,12 @@ describe('Test Unwinder', () => { label: 'B', overlay: { width: '100px', - height: '20px' - } - } - ] - } - ] + height: '20px', + }, + }, + ], + }, + ], }; const submission = { @@ -38,18 +38,18 @@ describe('Test Unwinder', () => { units: [ { a: 'one', - b: 'two' + b: 'two', }, { a: 'three', - b: 'four' + b: 'four', }, { a: 'five', - b: 'six' - } - ] - } + b: 'six', + }, + ], + }, }; const submissions = unwind(form, submission); @@ -61,34 +61,35 @@ describe('Test Unwinder', () => { units: [ { a: 'one', - b: 'two' - } - ] - } + b: 'two', + }, + ], + }, }); assert.deepEqual(submissions[1], { data: { units: [ { a: 'three', - b: 'four' - } - ] - } + b: 'four', + }, + ], + }, }); assert.deepEqual(submissions[2], { data: { units: [ { a: 'five', - b: 'six' - } - ] - } + b: 'six', + }, + ], + }, }); assert.deepEqual(rewind(submissions), submission); }); - it('Should unwind a form with nested datagrids and submission data', () => { + + it('Should unwind a form with nested datagrids and submission data', function () { const form = { components: [ { @@ -102,8 +103,8 @@ describe('Test Unwinder', () => { label: 'A', overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', @@ -111,8 +112,8 @@ describe('Test Unwinder', () => { label: 'B', overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'datagrid', @@ -125,14 +126,14 @@ describe('Test Unwinder', () => { label: 'C', overlay: { width: '100px', - height: '20px' - } - } - ] - } - ] - } - ] + height: '20px', + }, + }, + ], + }, + ], + }, + ], }; const submission = { @@ -143,28 +144,28 @@ describe('Test Unwinder', () => { b: 'two', subunits: [ { - c: 'three' + c: 'three', }, { - c: 'four' - } - ] + c: 'four', + }, + ], }, { a: 'five', b: 'six', subunits: [ { - c: 'seven' - } - ] + c: 'seven', + }, + ], }, { a: 'eight', - b: 'nine' - } - ] - } + b: 'nine', + }, + ], + }, }; const submissions = unwind(form, submission); @@ -177,12 +178,12 @@ describe('Test Unwinder', () => { b: 'two', subunits: [ { - c: 'three' - } - ] - } - ] - } + c: 'three', + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[1], { data: { @@ -192,12 +193,12 @@ describe('Test Unwinder', () => { b: 'two', subunits: [ { - c: 'four' - } - ] - } - ] - } + c: 'four', + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[2], { data: { @@ -207,26 +208,27 @@ describe('Test Unwinder', () => { b: 'six', subunits: [ { - c: 'seven' - } - ] - } - ] - } + c: 'seven', + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[3], { data: { units: [ { a: 'eight', - b: 'nine' - } - ] - } + b: 'nine', + }, + ], + }, }); assert.deepEqual(rewind(submissions), submission); }); - it('Should unwind a form with deep nested datagrids and submission data', () => { + + it('Should unwind a form with deep nested datagrids and submission data', function () { const form = { components: [ { @@ -240,8 +242,8 @@ describe('Test Unwinder', () => { label: 'A', overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', @@ -249,8 +251,8 @@ describe('Test Unwinder', () => { label: 'B', overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'datagrid', @@ -263,8 +265,8 @@ describe('Test Unwinder', () => { label: 'C', overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'datagrid', @@ -277,16 +279,16 @@ describe('Test Unwinder', () => { label: 'd', overlay: { width: '100px', - height: '20px' - } - } - ] - } - ] - } - ] - } - ] + height: '20px', + }, + }, + ], + }, + ], + }, + ], + }, + ], }; const submission = { @@ -300,18 +302,18 @@ describe('Test Unwinder', () => { c: 'three', deepgrid: [ { - d: 'four' + d: 'four', }, { - d: 'five' - } - ] + d: 'five', + }, + ], }, { c: 'six', - deepgrid: [] - } - ] + deepgrid: [], + }, + ], }, { a: 'seven', @@ -321,29 +323,29 @@ describe('Test Unwinder', () => { c: 'nine', deepgrid: [ { - d: 'ten' + d: 'ten', }, { - d: 'eleven' + d: 'eleven', }, { - d: 'twelve' - } - ] - } - ] + d: 'twelve', + }, + ], + }, + ], }, { a: 'thirteen', b: 'fourteen', subunits: [ { - c: 'fiveteen' - } - ] - } - ] - } + c: 'fiveteen', + }, + ], + }, + ], + }, }; const submissions = unwind(form, submission); @@ -359,14 +361,14 @@ describe('Test Unwinder', () => { c: 'three', deepgrid: [ { - d: 'four' - } - ] - } - ] - } - ] - } + d: 'four', + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[1], { data: { @@ -379,14 +381,14 @@ describe('Test Unwinder', () => { c: 'three', deepgrid: [ { - d: 'five' - } - ] - } - ] - } - ] - } + d: 'five', + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[2], { data: { @@ -397,12 +399,12 @@ describe('Test Unwinder', () => { subunits: [ { c: 'six', - deepgrid: [] - } - ] - } - ] - } + deepgrid: [], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[3], { data: { @@ -415,14 +417,14 @@ describe('Test Unwinder', () => { c: 'nine', deepgrid: [ { - d: 'ten' - } - ] - } - ] - } - ] - } + d: 'ten', + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[4], { data: { @@ -435,14 +437,14 @@ describe('Test Unwinder', () => { c: 'nine', deepgrid: [ { - d: 'eleven' - } - ] - } - ] - } - ] - } + d: 'eleven', + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[5], { data: { @@ -455,14 +457,14 @@ describe('Test Unwinder', () => { c: 'nine', deepgrid: [ { - d: 'twelve' - } - ] - } - ] - } - ] - } + d: 'twelve', + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[6], { data: { @@ -472,16 +474,17 @@ describe('Test Unwinder', () => { b: 'fourteen', subunits: [ { - c: 'fiveteen' - } - ] - } - ] - } + c: 'fiveteen', + }, + ], + }, + ], + }, }); assert.deepEqual(rewind(submissions), submission); }); - it('Should also handle fields with the multiple setting.', () => { + + it('Should also handle fields with the multiple setting.', function () { const form = { components: [ { @@ -495,8 +498,8 @@ describe('Test Unwinder', () => { label: 'A', overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', @@ -504,8 +507,8 @@ describe('Test Unwinder', () => { label: 'B', overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'datagrid', @@ -518,8 +521,8 @@ describe('Test Unwinder', () => { label: 'C', overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'datagrid', @@ -533,16 +536,16 @@ describe('Test Unwinder', () => { multiple: true, overlay: { width: '100px', - height: '20px' - } - } - ] - } - ] - } - ] - } - ] + height: '20px', + }, + }, + ], + }, + ], + }, + ], + }, + ], }; const submission = { @@ -556,18 +559,18 @@ describe('Test Unwinder', () => { c: '3', deepgrid: [ { - d: ['4', '5'] + d: ['4', '5'], }, { - d: ['6', '7', '8'] - } - ] + d: ['6', '7', '8'], + }, + ], }, { c: '9', - deepgrid: [] - } - ] + deepgrid: [], + }, + ], }, { a: '10', @@ -577,37 +580,37 @@ describe('Test Unwinder', () => { c: '12', deepgrid: [ { - d: ['13', '14'] + d: ['13', '14'], }, { - d: ['15'] + d: ['15'], }, { - d: ['16', '17', '18'] - } - ] + d: ['16', '17', '18'], + }, + ], }, { c: '19', deepgrid: [ { - d: ['20'] - } - ] - } - ] + d: ['20'], + }, + ], + }, + ], }, { a: '21', b: '22', subunits: [ { - c: '23' - } - ] - } - ] - } + c: '23', + }, + ], + }, + ], + }, }; const submissions = unwind(form, submission); @@ -623,14 +626,14 @@ describe('Test Unwinder', () => { c: '3', deepgrid: [ { - d: ['4'] - } - ] - } - ] - } - ] - } + d: ['4'], + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[1], { @@ -644,14 +647,14 @@ describe('Test Unwinder', () => { c: '3', deepgrid: [ { - d: ['5'] - } - ] - } - ] - } - ] - } + d: ['5'], + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[2], { @@ -665,14 +668,14 @@ describe('Test Unwinder', () => { c: '3', deepgrid: [ { - d: ['6'] - } - ] - } - ] - } - ] - } + d: ['6'], + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[3], { @@ -686,14 +689,14 @@ describe('Test Unwinder', () => { c: '3', deepgrid: [ { - d: ['7'] - } - ] - } - ] - } - ] - } + d: ['7'], + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[4], { @@ -707,14 +710,14 @@ describe('Test Unwinder', () => { c: '3', deepgrid: [ { - d: ['8'] - } - ] - } - ] - } - ] - } + d: ['8'], + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[5], { @@ -726,12 +729,12 @@ describe('Test Unwinder', () => { subunits: [ { c: '9', - deepgrid: [] - } - ] - } - ] - } + deepgrid: [], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[6], { @@ -745,14 +748,14 @@ describe('Test Unwinder', () => { c: '12', deepgrid: [ { - d: ['13'] - } - ] - } - ] - } - ] - } + d: ['13'], + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[7], { @@ -766,14 +769,14 @@ describe('Test Unwinder', () => { c: '12', deepgrid: [ { - d: ['14'] - } - ] - } - ] - } - ] - } + d: ['14'], + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[8], { @@ -787,14 +790,14 @@ describe('Test Unwinder', () => { c: '12', deepgrid: [ { - d: ['15'] - } - ] - } - ] - } - ] - } + d: ['15'], + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[9], { @@ -808,14 +811,14 @@ describe('Test Unwinder', () => { c: '12', deepgrid: [ { - d: ['16'] - } - ] - } - ] - } - ] - } + d: ['16'], + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[10], { @@ -829,14 +832,14 @@ describe('Test Unwinder', () => { c: '12', deepgrid: [ { - d: ['17'] - } - ] - } - ] - } - ] - } + d: ['17'], + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[11], { @@ -850,14 +853,14 @@ describe('Test Unwinder', () => { c: '12', deepgrid: [ { - d: ['18'] - } - ] - } - ] - } - ] - } + d: ['18'], + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[12], { @@ -871,14 +874,14 @@ describe('Test Unwinder', () => { c: '19', deepgrid: [ { - d: ['20'] - } - ] - } - ] - } - ] - } + d: ['20'], + }, + ], + }, + ], + }, + ], + }, }); assert.deepEqual(submissions[13], { @@ -889,16 +892,17 @@ describe('Test Unwinder', () => { b: '22', subunits: [ { - c: '23' - } - ] - } - ] - } + c: '23', + }, + ], + }, + ], + }, }); assert.deepEqual(rewind(submissions), submission); }); - it('Should allow the path variable within the components.', () => { + + it('Should allow the path variable within the components.', function () { const form = { components: [ { @@ -906,62 +910,62 @@ describe('Test Unwinder', () => { key: 'a1', label: 'a1', properties: { - dataPath: 'units[0].a' + dataPath: 'units[0].a', }, overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', key: 'a2', label: 'a2', properties: { - dataPath: 'units[1].a' + dataPath: 'units[1].a', }, overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', key: 'b1', label: 'b1', properties: { - dataPath: 'units[0].b' + dataPath: 'units[0].b', }, overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', key: 'b2', label: 'b2', properties: { - dataPath: 'units[1].b' + dataPath: 'units[1].b', }, overlay: { width: '100px', - height: '20px' - } - } - ] + height: '20px', + }, + }, + ], }; const submission = { data: { units: [ - {a: '1', b: '2'}, - {a: '3', b: '4'}, - {a: '5', b: '6'}, - {a: '7', b: '8'}, - {a: '9', b: '10'} - ] - } + { a: '1', b: '2' }, + { a: '3', b: '4' }, + { a: '5', b: '6' }, + { a: '7', b: '8' }, + { a: '9', b: '10' }, + ], + }, }; const submissions = unwind(form, submission); @@ -973,29 +977,28 @@ describe('Test Unwinder', () => { assert.deepEqual(submissions[0], { data: { units: [ - {a: '1', b: '2'}, - {a: '3', b: '4'} - ] - } + { a: '1', b: '2' }, + { a: '3', b: '4' }, + ], + }, }); assert.deepEqual(submissions[1], { data: { units: [ - {a: '5', b: '6'}, - {a: '7', b: '8'} - ] - } + { a: '5', b: '6' }, + { a: '7', b: '8' }, + ], + }, }); assert.deepEqual(submissions[2], { data: { - units: [ - {a: '9', b: '10'} - ] - } + units: [{ a: '9', b: '10' }], + }, }); assert.deepEqual(rewind(submissions), submission); }); - it('Should allow complex path variables within the components.', () => { + + it('Should allow complex path variables within the components.', function () { const form = { components: [ { @@ -1003,175 +1006,183 @@ describe('Test Unwinder', () => { key: 'a1', label: 'a1', properties: { - dataPath: 'units[0].a' + dataPath: 'units[0].a', }, overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', key: 'sub1c1', label: 'sub1c1', properties: { - dataPath: 'units[0].sub[0].c' + dataPath: 'units[0].sub[0].c', }, overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', key: 'sub1c2', label: 'sub1c2', properties: { - dataPath: 'units[0].sub[1].c' + dataPath: 'units[0].sub[1].c', }, overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', key: 'sub1d1', label: 'sub1d1', properties: { - dataPath: 'units[0].sub[0].d' + dataPath: 'units[0].sub[0].d', }, overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', key: 'sub1d2', label: 'sub1d2', properties: { - dataPath: 'units[0].sub[1].d' + dataPath: 'units[0].sub[1].d', }, overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', key: 'a2', label: 'a2', properties: { - dataPath: 'units[1].a' + dataPath: 'units[1].a', }, overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', key: 'sub2c1', label: 'sub2c1', properties: { - dataPath: 'units[1].sub[0].c' + dataPath: 'units[1].sub[0].c', }, overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', key: 'sub2c2', label: 'sub2c2', properties: { - dataPath: 'units[1].sub[1].c' + dataPath: 'units[1].sub[1].c', }, overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', key: 'sub2d1', label: 'sub2d1', properties: { - dataPath: 'units[1].sub[0].d' + dataPath: 'units[1].sub[0].d', }, overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', key: 'sub2d2', label: 'sub2d2', properties: { - dataPath: 'units[1].sub[1].d' + dataPath: 'units[1].sub[1].d', }, overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', key: 'b1', label: 'b1', properties: { - dataPath: 'units[0].b' + dataPath: 'units[0].b', }, overlay: { width: '100px', - height: '20px' - } + height: '20px', + }, }, { type: 'textfield', key: 'b2', label: 'b2', properties: { - dataPath: 'units[1].b' + dataPath: 'units[1].b', }, overlay: { width: '100px', - height: '20px' - } - } - ] + height: '20px', + }, + }, + ], }; const submission = { data: { units: [ - {a: '1', b: '2', sub: [ - {c: '3', d: '4'}, - {c: '5', d: '6'}, - {c: '7', d: '8'} - ]}, - {a: '9', b: '10', sub: [ - {c: '11', d: '12'}, - {c: '13', d: '14'}, - {c: '15', d: '16'} - ]}, - {a: '15', b: '16', sub: [ - {c: '17'} - ]}, - {a: '18', b: '19', sub: [ - {c: '20', d: '21'} - ]}, - {a: '22', b: '23', sub: [ - {c: '24', d: '25'}, - {c: '26', d: '27'}, - {c: '28', d: '29'}, - {c: '30', d: '31'} - ]} - ] - } + { + a: '1', + b: '2', + sub: [ + { c: '3', d: '4' }, + { c: '5', d: '6' }, + { c: '7', d: '8' }, + ], + }, + { + a: '9', + b: '10', + sub: [ + { c: '11', d: '12' }, + { c: '13', d: '14' }, + { c: '15', d: '16' }, + ], + }, + { a: '15', b: '16', sub: [{ c: '17' }] }, + { a: '18', b: '19', sub: [{ c: '20', d: '21' }] }, + { + a: '22', + b: '23', + sub: [ + { c: '24', d: '25' }, + { c: '26', d: '27' }, + { c: '28', d: '29' }, + { c: '30', d: '31' }, + ], + }, + ], + }, }; const submissions = unwind(form, submission); @@ -1179,60 +1190,68 @@ describe('Test Unwinder', () => { assert.deepEqual(submissions[0], { data: { units: [ - {a: '1', b: '2', sub: [ - {c: '3', d: '4'}, - {c: '5', d: '6'} - ]}, - {a: '9', b: '10', sub: [ - {c: '11', d: '12'}, - {c: '13', d: '14'} - ]} - ] - } + { + a: '1', + b: '2', + sub: [ + { c: '3', d: '4' }, + { c: '5', d: '6' }, + ], + }, + { + a: '9', + b: '10', + sub: [ + { c: '11', d: '12' }, + { c: '13', d: '14' }, + ], + }, + ], + }, }); assert.deepEqual(submissions[1], { data: { units: [ - {a: '1', b: '2', sub: [ - {c: '7', d: '8'} - ]}, - {a: '9', b: '10', sub: [ - {c: '15', d: '16'} - ]} - ] - } + { a: '1', b: '2', sub: [{ c: '7', d: '8' }] }, + { a: '9', b: '10', sub: [{ c: '15', d: '16' }] }, + ], + }, }); assert.deepEqual(submissions[2], { data: { units: [ - {a: '15', b: '16', sub: [ - {c: '17'} - ]}, - {a: '18', b: '19', sub: [ - {c: '20', d: '21'} - ]} - ] - } + { a: '15', b: '16', sub: [{ c: '17' }] }, + { a: '18', b: '19', sub: [{ c: '20', d: '21' }] }, + ], + }, }); assert.deepEqual(submissions[3], { data: { units: [ - {a: '22', b: '23', sub: [ - {c: '24', d: '25'}, - {c: '26', d: '27'} - ]} - ] - } + { + a: '22', + b: '23', + sub: [ + { c: '24', d: '25' }, + { c: '26', d: '27' }, + ], + }, + ], + }, }); assert.deepEqual(submissions[4], { data: { units: [ - {a: '22', b: '23', sub: [ - {c: '28', d: '29'}, - {c: '30', d: '31'} - ]} - ] - } + { + a: '22', + b: '23', + sub: [ + { c: '28', d: '29' }, + { c: '30', d: '31' }, + ], + }, + ], + }, }); assert.deepEqual(rewind(submissions), submission); }); diff --git a/src/utils/conditions.ts b/src/utils/conditions.ts index 6c11d04b..d1d4cd78 100644 --- a/src/utils/conditions.ts +++ b/src/utils/conditions.ts @@ -1,30 +1,30 @@ -import { ConditionsContext, JSONConditional, LegacyConditional, SimpleConditional } from "types"; +import { ConditionsContext, JSONConditional, LegacyConditional, SimpleConditional } from 'types'; import { EvaluatorFn, evaluate, JSONLogicEvaluator } from 'modules/jsonlogic'; -import { flattenComponents, getComponent, getComponentActualValue } from "./formUtil"; +import { flattenComponents, getComponent, getComponentActualValue } from './formUtil'; import { has, isObject, map, every, some, find, filter, isBoolean, split } from 'lodash'; import ConditionOperators from './operators'; export const isJSONConditional = (conditional: any): conditional is JSONConditional => { - return conditional && conditional.json && isObject(conditional.json); -} + return conditional && conditional.json && isObject(conditional.json); +}; export const isLegacyConditional = (conditional: any): conditional is LegacyConditional => { - return conditional && conditional.when; -} + return conditional && conditional.when; +}; export const isSimpleConditional = (conditional: any): conditional is SimpleConditional => { - return conditional && conditional.conjunction && conditional.conditions; -} + return conditional && conditional.conjunction && conditional.conditions; +}; export function conditionallyHidden(context: ConditionsContext) { - const { scope, path } = context; - if (scope.conditionals && path) { - const hidden = find(scope.conditionals, (conditional) => { - return conditional.path === path; - }); - return hidden?.conditionallyHidden; - } - return false; + const { scope, path } = context; + if (scope.conditionals && path) { + const hidden = find(scope.conditionals, (conditional) => { + return conditional.path === path; + }); + return hidden?.conditionallyHidden; + } + return false; } /** @@ -36,16 +36,20 @@ export function conditionallyHidden(context: ConditionsContext) { * @param data * @returns {*} */ -export function checkCustomConditional(condition: string, context: ConditionsContext, variable: string = 'show'): boolean | null { - const { evalContext } = context; - if (!condition) { - return null; - } - const value = evaluate(context, condition, variable, evalContext as EvaluatorFn); - if (value === null) { - return null; - } - return value; +export function checkCustomConditional( + condition: string, + context: ConditionsContext, + variable: string = 'show', +): boolean | null { + const { evalContext } = context; + if (!condition) { + return null; + } + const value = evaluate(context, condition, variable, evalContext as EvaluatorFn); + if (value === null) { + return null; + } + return value; } /** @@ -56,21 +60,24 @@ export function checkCustomConditional(condition: string, context: ConditionsCon * @param checkDefault * @returns */ -export function checkLegacyConditional(conditional: LegacyConditional, context: ConditionsContext): boolean | null { - const { row, data, component } = context; - if (!conditional || !isLegacyConditional(conditional) || !conditional.when) { - return null; - } - const value: any = getComponentActualValue(component, conditional.when, data, row); - const eq = String(conditional.eq); - const show = String(conditional.show); - if (isObject(value) && has(value, eq)) { - return String((value as Record)[eq]) === show; - } - if (Array.isArray(value) && value.map(String).includes(eq)) { - return show === 'true'; - } - return (String(value) === eq) === (show === 'true'); +export function checkLegacyConditional( + conditional: LegacyConditional, + context: ConditionsContext, +): boolean | null { + const { row, data, component } = context; + if (!conditional || !isLegacyConditional(conditional) || !conditional.when) { + return null; + } + const value: any = getComponentActualValue(component, conditional.when, data, row); + const eq = String(conditional.eq); + const show = String(conditional.show); + if (isObject(value) && has(value, eq)) { + return String((value as Record)[eq]) === show; + } + if (Array.isArray(value) && value.map(String).includes(eq)) { + return show === 'true'; + } + return (String(value) === eq) === (show === 'true'); } /** @@ -79,13 +86,16 @@ export function checkLegacyConditional(conditional: LegacyConditional, context: * @param context * @returns */ -export function checkJsonConditional(conditional: JSONConditional, context: ConditionsContext): boolean | null { - const { evalContext } = context; - if (!conditional || !isJSONConditional(conditional)) { - return null; - } - const evalContextValue = evalContext ? evalContext(context) : context; - return JSONLogicEvaluator.evaluate(conditional.json, evalContextValue); +export function checkJsonConditional( + conditional: JSONConditional, + context: ConditionsContext, +): boolean | null { + const { evalContext } = context; + if (!conditional || !isJSONConditional(conditional)) { + return null; + } + const evalContextValue = evalContext ? evalContext(context) : context; + return JSONLogicEvaluator.evaluate(conditional.json, evalContextValue); } /** @@ -94,14 +104,17 @@ export function checkJsonConditional(conditional: JSONConditional, context: Cond * @returns {boolean} */ function isConditionPotentiallyBasedOnValuePath(condition: any = {}) { - let comparedValue; - try { - comparedValue = JSON.parse(condition.value); - } - catch(e) { - comparedValue = condition.value; - } - return isBoolean(comparedValue) && (condition.component || '').split('.').length > 1 && condition.operator === 'isEqual'; + let comparedValue; + try { + comparedValue = JSON.parse(condition.value); + } catch (ignoreError) { + comparedValue = condition.value; + } + return ( + isBoolean(comparedValue) && + (condition.component || '').split('.').length > 1 && + condition.operator === 'isEqual' + ); } /** @@ -110,64 +123,91 @@ function isConditionPotentiallyBasedOnValuePath(condition: any = {}) { * @param context * @returns */ -export function checkSimpleConditional(conditional: SimpleConditional, context: ConditionsContext): boolean | null { - const { component, data, row, instance, form } = context; - if (!conditional || !isSimpleConditional(conditional)) { - return null; - } - const { conditions = [], conjunction = 'all', show = true } = conditional; - if (!conditions.length) { +export function checkSimpleConditional( + conditional: SimpleConditional, + context: ConditionsContext, +): boolean | null { + const { component, data, row, instance, form } = context; + if (!conditional || !isSimpleConditional(conditional)) { + return null; + } + const { conditions = [], conjunction = 'all', show = true } = conditional; + if (!conditions.length) { + return null; + } + + const conditionsResult = filter( + map(conditions, (cond) => { + const { operator } = cond; + let { value: comparedValue, component: conditionComponentPath } = cond; + if (!conditionComponentPath) { + // Ignore conditions if there is no component path. return null; - } + } + const formComponents = form?.components || []; + let conditionComponent = getComponent(formComponents, conditionComponentPath, true); + // If condition componenet is not found, check if conditionComponentPath is value path. + // Need to handle condtions like: + // { + // "component": "selectBoxes.a", + // "operator": "isEqual", + // "value": "true" + // } + if ( + !conditionComponent && + isConditionPotentiallyBasedOnValuePath(cond) && + formComponents.length + ) { + const flattenedComponents = flattenComponents(formComponents, true); + const pathParts = split(conditionComponentPath, '.'); + const valuePathParts = []; - const conditionsResult = filter(map(conditions, (cond) => { - let { value: comparedValue, operator, component: conditionComponentPath } = cond; - if (!conditionComponentPath) { - // Ignore conditions if there is no component path. - return null; + while (!conditionComponent && pathParts.length) { + conditionComponent = flattenedComponents[`${pathParts.join('.')}`]; + if (!conditionComponent) { + valuePathParts.unshift(pathParts.pop()); + } } - const formComponents = form?.components || []; - let conditionComponent = getComponent(formComponents, conditionComponentPath, true); - // If condition componenet is not found, check if conditionComponentPath is value path. - // Need to handle condtions like: - // { - // "component": "selectBoxes.a", - // "operator": "isEqual", - // "value": "true" - // } - if (!conditionComponent && isConditionPotentiallyBasedOnValuePath(cond) && formComponents.length) { - const flattenedComponents = flattenComponents(formComponents, true); - const pathParts = split(conditionComponentPath, '.'); - const valuePathParts = []; - - while (!conditionComponent && pathParts.length) { - conditionComponent = flattenedComponents[`${pathParts.join('.')}`]; - if (!conditionComponent) { - valuePathParts.unshift(pathParts.pop()); - } - } - if (conditionComponent && conditionComponent.type === 'selectboxes' && valuePathParts.length) { - console.warn('Condition based on selectboxes has wrong format. Resave the form in the form builder to fix it.'); - conditionComponentPath = pathParts.join('.'); - comparedValue = valuePathParts.join('.'); - } + if ( + conditionComponent && + conditionComponent.type === 'selectboxes' && + valuePathParts.length + ) { + console.warn( + 'Condition based on selectboxes has wrong format. Resave the form in the form builder to fix it.', + ); + conditionComponentPath = pathParts.join('.'); + comparedValue = valuePathParts.join('.'); } + } - const value = conditionComponent ? getComponentActualValue(conditionComponent, conditionComponentPath, data, row) : null; + const value = conditionComponent + ? getComponentActualValue(conditionComponent, conditionComponentPath, data, row) + : null; - const ConditionOperator = ConditionOperators[operator]; - return ConditionOperator - ? new ConditionOperator().getResult({ value, comparedValue, instance, component, conditionComponent, conditionComponentPath, data}) - : true; - }), (res) => (res !== null)); + const ConditionOperator = ConditionOperators[operator]; + return ConditionOperator + ? new ConditionOperator().getResult({ + value, + comparedValue, + instance, + component, + conditionComponent, + conditionComponentPath, + data, + }) + : true; + }), + (res) => res !== null, + ); - let result = false; - switch (conjunction) { - case 'any': - result = some(conditionsResult, res => !!res); - break; - default: - result = every(conditionsResult, res => !!res); - } - return show ? result : !result; + let result = false; + switch (conjunction) { + case 'any': + result = some(conditionsResult, (res) => !!res); + break; + default: + result = every(conditionsResult, (res) => !!res); + } + return show ? result : !result; } diff --git a/src/utils/date.ts b/src/utils/date.ts index bb3d69e9..440004fe 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -18,7 +18,7 @@ dayjs.extend(customParseFormat); * @return {string} */ export function currentTimezone(): string { - return dayjs.tz.guess(); + return dayjs.tz.guess(); } /** @@ -27,17 +27,19 @@ export function currentTimezone(): string { * @return {string} */ export function convertFormatToMoment(format: string) { - return format - // Year conversion. - .replace(/y/g, 'Y') - // Day in month. - .replace(/d/g, 'D') - // Day in week. - .replace(/E/g, 'd') - // AM/PM marker - .replace(/a/g, 'A') - // Unix Timestamp - .replace(/U/g, 'X'); + return ( + format + // Year conversion. + .replace(/y/g, 'Y') + // Day in month. + .replace(/d/g, 'D') + // Day in week. + .replace(/E/g, 'd') + // AM/PM marker + .replace(/a/g, 'A') + // Unix Timestamp + .replace(/U/g, 'X') + ); } /** @@ -49,14 +51,14 @@ export function convertFormatToMoment(format: string) { * @return {*} */ export function momentDate(value: any, format: any, timezone: any): any { - const momentDate = dayjs(value); - if (timezone === 'UTC') { - return dayjs.utc(); - } - if (timezone !== currentTimezone() || (format && format.match(/\s(z$|z\s)/))) { - return momentDate.tz(timezone); - } - return momentDate; + const momentDate = dayjs(value); + if (timezone === 'UTC') { + return dayjs.utc(); + } + if (timezone !== currentTimezone() || (format && format.match(/\s(z$|z\s)/))) { + return momentDate.tz(timezone); + } + return momentDate; } /** @@ -68,16 +70,16 @@ export function momentDate(value: any, format: any, timezone: any): any { * @return {string} */ export function formatDate(value: ConfigType, format: string, timezone?: string): string { - const date = dayjs(value); - const dayjsFormat = convertFormatToMoment(format); - - if (timezone === 'UTC') { - return `${date.utc().format(dayjsFormat)} UTC`; - } - if (timezone) { - return date.tz(timezone).format(`${dayjsFormat} z`); - } - return date.format(dayjsFormat); + const date = dayjs(value); + const dayjsFormat = convertFormatToMoment(format); + + if (timezone === 'UTC') { + return `${date.utc().format(dayjsFormat)} UTC`; + } + if (timezone) { + return date.tz(timezone).format(`${dayjsFormat} z`); + } + return date.format(dayjsFormat); } /** @@ -87,62 +89,58 @@ export function formatDate(value: ConfigType, format: string, timezone?: string) * @return {(null|Date)} */ export function getDateSetting(date: any) { - if (isNil(date) || isNaN(date) || date === '') { - return null; - } - - if (date instanceof Date) { - return date; - } - else if (typeof date.toDate === 'function') { - return date.isValid() ? date.toDate() : null; - } - - let dateSetting = ((typeof date !== 'string') || (date.indexOf('moment(') === -1)) ? dayjs(date) : null; - if (dateSetting && dateSetting.isValid()) { - return dateSetting.toDate(); + if (isNil(date) || isNaN(date) || date === '') { + return null; + } + + if (date instanceof Date) { + return date; + } else if (typeof date.toDate === 'function') { + return date.isValid() ? date.toDate() : null; + } + + let dateSetting = typeof date !== 'string' || date.indexOf('moment(') === -1 ? dayjs(date) : null; + if (dateSetting && dateSetting.isValid()) { + return dateSetting.toDate(); + } + + dateSetting = null; + try { + const value = Evaluator.evaluator(`return ${date};`, 'moment')(dayjs); + if (typeof value === 'string') { + dateSetting = dayjs(value); + } else if (typeof value.toDate === 'function') { + dateSetting = dayjs(value.toDate().toUTCString()); + } else if (value instanceof Date) { + dateSetting = dayjs(value); } + } catch (ignoreError) { + return null; + } - dateSetting = null; - try { - const value = Evaluator.evaluator(`return ${date};`, 'moment')(dayjs); - if (typeof value === 'string') { - dateSetting = dayjs(value); - } - else if (typeof value.toDate === 'function') { - dateSetting = dayjs(value.toDate().toUTCString()); - } - else if (value instanceof Date) { - dateSetting = dayjs(value); - } - } - catch (e) { - return null; - } + if (!dateSetting) { + return null; + } - if (!dateSetting) { - return null; - } + // Ensure this is a date. + if (!dateSetting.isValid()) { + return null; + } - // Ensure this is a date. - if (!dateSetting.isValid()) { - return null; - } - - return dateSetting.toDate(); + return dateSetting.toDate(); } export const getDateValidationFormat = (component: DayComponent) => { - return component.dayFirst ? 'DD-MM-YYYY' : 'MM-DD-YYYY'; + return component.dayFirst ? 'DD-MM-YYYY' : 'MM-DD-YYYY'; }; export const isPartialDay = (component: DayComponent, value: string | undefined) => { - if (!value) { - return true; - } - const [DAY, MONTH, YEAR] = component.dayFirst ? [0, 1, 2] : [1, 0, 2]; - const values = value.split('/'); - return values[DAY] === '00' || values[MONTH] === '00' || values[YEAR] === '0000'; + if (!value) { + return true; + } + const [DAY, MONTH, YEAR] = component.dayFirst ? [0, 1, 2] : [1, 0, 2]; + const values = value.split('/'); + return values[DAY] === '00' || values[MONTH] === '00' || values[YEAR] === '0000'; }; export { dayjs }; diff --git a/src/utils/dom.ts b/src/utils/dom.ts index 5e290e97..96060be4 100644 --- a/src/utils/dom.ts +++ b/src/utils/dom.ts @@ -4,10 +4,10 @@ * @param element * @param container */ -export function appendTo(element: (HTMLElement | undefined), container: (HTMLElement | undefined)) { - if (container && element) { - container?.appendChild(element); - } +export function appendTo(element: HTMLElement | undefined, container: HTMLElement | undefined) { + if (container && element) { + container?.appendChild(element); + } } /** @@ -16,21 +16,19 @@ export function appendTo(element: (HTMLElement | undefined), container: (HTMLEle * @param {HTMLElement} element - The DOM element to prepend. * @param {HTMLElement} container - The DOM element that is the container of the element getting prepended. */ -export function prependTo(element: (HTMLElement | undefined), container: (HTMLElement | undefined)) { - if (container && element) { - if (container.firstChild) { - try { - container.insertBefore(element, container.firstChild); - } - catch (err) { - console.warn(err); - container.appendChild(element); - } - } - else { - container.appendChild(element); - } +export function prependTo(element: HTMLElement | undefined, container: HTMLElement | undefined) { + if (container && element) { + if (container.firstChild) { + try { + container.insertBefore(element, container.firstChild); + } catch (err) { + console.warn(err); + container.appendChild(element); + } + } else { + container.appendChild(element); } + } } /** @@ -39,15 +37,17 @@ export function prependTo(element: (HTMLElement | undefined), container: (HTMLEl * @param {HTMLElement} element - The element to remove. * @param {HTMLElement} container - The DOM element that is the container of the element to remove. */ -export function removeChildFrom(element: (HTMLElement | undefined), container: (HTMLElement | undefined)) { - if (container && element && container.contains(element)) { - try { - container.removeChild(element); - } - catch (err) { - console.warn(err); - } +export function removeChildFrom( + element: HTMLElement | undefined, + container: HTMLElement | undefined, +) { + if (container && element && container.contains(element)) { + try { + container.removeChild(element); + } catch (err) { + console.warn(err); } + } } /** @@ -55,10 +55,10 @@ export function removeChildFrom(element: (HTMLElement | undefined), container: ( * * @param {HTMLElement} element - The element you wish to empty. */ -export function empty(element: (HTMLElement | undefined)) { - if (element) { - while (element.firstChild) { - element.removeChild(element.firstChild); - } +export function empty(element: HTMLElement | undefined) { + if (element) { + while (element.firstChild) { + element.removeChild(element.firstChild); } -} \ No newline at end of file + } +} diff --git a/src/utils/error.ts b/src/utils/error.ts index a98993de..3e47ad80 100644 --- a/src/utils/error.ts +++ b/src/utils/error.ts @@ -1,6 +1,6 @@ export function getErrorMessage(error: unknown) { - if (error instanceof Error) { - return error.message; - } - return String(error); + if (error instanceof Error) { + return error.message; + } + return String(error); } diff --git a/src/utils/fastCloneDeep.ts b/src/utils/fastCloneDeep.ts index 30d03ce4..d81192d3 100644 --- a/src/utils/fastCloneDeep.ts +++ b/src/utils/fastCloneDeep.ts @@ -4,11 +4,10 @@ * @param obj */ export function fastCloneDeep(obj: any) { - try { - return JSON.parse(JSON.stringify(obj)); - } - catch (err: any) { - console.log(`Clone Failed: ${err.message}`); - return null; - } -} \ No newline at end of file + try { + return JSON.parse(JSON.stringify(obj)); + } catch (err: any) { + console.log(`Clone Failed: ${err.message}`); + return null; + } +} diff --git a/src/utils/formUtil/eachComponent.ts b/src/utils/formUtil/eachComponent.ts index 7e2a0f3f..ee9a6b5b 100644 --- a/src/utils/formUtil/eachComponent.ts +++ b/src/utils/formUtil/eachComponent.ts @@ -1,5 +1,5 @@ -import { Component, EachComponentCallback } from "types"; -import { componentInfo, componentPath, componentFormPath } from "./index"; +import { Component, EachComponentCallback } from 'types'; +import { componentInfo, componentPath, componentFormPath } from './index'; /** * Iterate through each component within a form. @@ -16,87 +16,75 @@ import { componentInfo, componentPath, componentFormPath } from "./index"; * The parent object. */ export function eachComponent( - components: Component[], - fn: EachComponentCallback, - includeAll?: boolean, - path: string = "", - parent?: Component, - ) { - if (!components) return; - components.forEach((component: any) => { - if (!component) { - return; - } - const info = componentInfo(component); - let noRecurse = false; - // Keep track of parent references. - if (parent) { - // Ensure we don't create infinite JSON structures. - Object.defineProperty(component, 'parent', { - enumerable: false, - writable: true, - value: JSON.parse(JSON.stringify(parent)) - }); - Object.defineProperty(component.parent, 'parent', { - enumerable: false, - writable: true, - value: parent.parent - }); - Object.defineProperty(component.parent, 'path', { - enumerable: false, - writable: true, - value: parent.path - }); - delete component.parent.components; - delete component.parent.componentMap; - delete component.parent.columns; - delete component.parent.rows; - } - - Object.defineProperty(component, 'path', { + components: Component[], + fn: EachComponentCallback, + includeAll?: boolean, + path: string = '', + parent?: Component, +) { + if (!components) return; + components.forEach((component: any) => { + if (!component) { + return; + } + const info = componentInfo(component); + let noRecurse = false; + // Keep track of parent references. + if (parent) { + // Ensure we don't create infinite JSON structures. + Object.defineProperty(component, 'parent', { + enumerable: false, + writable: true, + value: JSON.parse(JSON.stringify(parent)), + }); + Object.defineProperty(component.parent, 'parent', { enumerable: false, writable: true, - value: componentPath(component, path) + value: parent.parent, }); + Object.defineProperty(component.parent, 'path', { + enumerable: false, + writable: true, + value: parent.path, + }); + delete component.parent.components; + delete component.parent.componentMap; + delete component.parent.columns; + delete component.parent.rows; + } - if (includeAll || component.tree || !info.layout) { - noRecurse = !!fn(component, component.path, components, parent); - } + Object.defineProperty(component, 'path', { + enumerable: false, + writable: true, + value: componentPath(component, path), + }); + + if (includeAll || component.tree || !info.layout) { + noRecurse = !!fn(component, component.path, components, parent); + } - if (!noRecurse) { - if (info.hasColumns) { - component.columns.forEach((column: any) => - 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, - ) - ); - } - }); - } else if (info.hasComps) { - eachComponent( - component.components, - fn, - includeAll, - componentFormPath(component, path, component.path), - parent ? component : null, - ); - } + if (!noRecurse) { + if (info.hasColumns) { + component.columns.forEach((column: any) => + 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), + ); + } + }); + } else if (info.hasComps) { + eachComponent( + component.components, + fn, + includeAll, + componentFormPath(component, path, component.path), + parent ? component : null, + ); } - }); - } + } + }); +} diff --git a/src/utils/formUtil/eachComponentAsync.ts b/src/utils/formUtil/eachComponentAsync.ts index 18cdd8d4..a2686397 100644 --- a/src/utils/formUtil/eachComponentAsync.ts +++ b/src/utils/formUtil/eachComponentAsync.ts @@ -1,85 +1,86 @@ -import { componentInfo, componentPath, componentFormPath } from "./index"; +import { componentInfo, componentPath, componentFormPath } from './index'; // Async each component. export async function eachComponentAsync( - components: any[], - fn: any, - includeAll = false, - path = "", - parent?: any - ) { - if (!components) return; - for (let i = 0; i < components.length; i++) { - if (!components[i]) { - continue; - } - let component = components[i]; - const info = componentInfo(component); - // Keep track of parent references. - if (parent) { - // Ensure we don't create infinite JSON structures. - Object.defineProperty(component, 'parent', { - enumerable: false, - writable: true, - value: JSON.parse(JSON.stringify(parent)) - }); - Object.defineProperty(component.parent, 'parent', { - enumerable: false, - writable: true, - value: parent.parent - }); - Object.defineProperty(component.parent, 'path', { - enumerable: false, - writable: true, - value: parent.path - }); - delete component.parent.components; - delete component.parent.componentMap; - delete component.parent.columns; - delete component.parent.rows; - } - Object.defineProperty(component, 'path', { + components: any[], + fn: any, + includeAll = false, + path = '', + parent?: any, +) { + if (!components) return; + for (let i = 0; i < components.length; i++) { + if (!components[i]) { + continue; + } + const component = components[i]; + const info = componentInfo(component); + // Keep track of parent references. + if (parent) { + // Ensure we don't create infinite JSON structures. + Object.defineProperty(component, 'parent', { enumerable: false, writable: true, - value: componentPath(component, path) + value: JSON.parse(JSON.stringify(parent)), }); - if (includeAll || component.tree || !info.layout) { - if (await fn(component, component.path, components, parent)) { - continue; - } + Object.defineProperty(component.parent, 'parent', { + enumerable: false, + writable: true, + value: parent.parent, + }); + Object.defineProperty(component.parent, 'path', { + enumerable: false, + writable: true, + value: parent.path, + }); + delete component.parent.components; + delete component.parent.componentMap; + delete component.parent.columns; + delete component.parent.rows; + } + Object.defineProperty(component, 'path', { + enumerable: false, + writable: true, + value: componentPath(component, path), + }); + if (includeAll || component.tree || !info.layout) { + if (await fn(component, component.path, components, parent)) { + continue; } - if (info.hasColumns) { - for (let j = 0; j < component.columns.length; j++) { - await eachComponentAsync( - component.columns[j]?.components, - fn, - includeAll, - path, - parent ? component : null - ); - } - } else if (info.hasRows) { - for (let j = 0; j < component.rows.length; j++) { - let row = component.rows[j]; - if (Array.isArray(row)) { - for (let k = 0; k < row.length; k++) { - await eachComponentAsync( - row[k]?.components, - fn, includeAll, - path, - parent ? component : null - ); - } - } - } - } else if (info.hasComps) { + } + if (info.hasColumns) { + for (let j = 0; j < component.columns.length; j++) { await eachComponentAsync( - component.components, + component.columns[j]?.components, fn, includeAll, - componentFormPath(component, path, component.path), - parent ? component : null + path, + parent ? component : null, ); } + } else if (info.hasRows) { + for (let j = 0; j < component.rows.length; j++) { + const row = component.rows[j]; + if (Array.isArray(row)) { + for (let k = 0; k < row.length; k++) { + await eachComponentAsync( + row[k]?.components, + fn, + includeAll, + path, + parent ? component : null, + ); + } + } + } + } else if (info.hasComps) { + await eachComponentAsync( + component.components, + fn, + includeAll, + componentFormPath(component, path, component.path), + parent ? component : null, + ); } } +} diff --git a/src/utils/formUtil/eachComponentData.ts b/src/utils/formUtil/eachComponentData.ts index f1a44bed..10e4a673 100644 --- a/src/utils/formUtil/eachComponentData.ts +++ b/src/utils/formUtil/eachComponentData.ts @@ -1,104 +1,147 @@ -import { isEmpty, get, set, has } from "lodash"; +import { isEmpty, get, set, has } from 'lodash'; -import { Component, DataObject, EachComponentDataCallback, HasChildComponents, HasColumns, HasRows } from "types"; -import { getContextualRowData, isComponentNestedDataType, getModelType, componentDataPath, componentInfo, componentFormPath } from "./index"; -import { eachComponent } from "./eachComponent"; +import { + Component, + DataObject, + EachComponentDataCallback, + HasChildComponents, + HasColumns, + HasRows, +} from 'types'; +import { + getContextualRowData, + isComponentNestedDataType, + getModelType, + componentDataPath, + componentInfo, + componentFormPath, +} from './index'; +import { eachComponent } from './eachComponent'; export const eachComponentData = ( - components: Component[], - data: DataObject, - fn: EachComponentDataCallback, - path = "", - index?: number, - parent?: Component, - includeAll: boolean = false, - ) => { - if (!components || !data) { - return; - } - return eachComponent( - components, - (component, compPath, componentComponents, compParent) => { - const row = getContextualRowData(component, compPath, data); - if (fn(component, data, row, compPath, componentComponents, index, compParent) === true) { + components: Component[], + data: DataObject, + fn: EachComponentDataCallback, + path = '', + index?: number, + parent?: Component, + includeAll: boolean = false, +) => { + if (!components || !data) { + return; + } + return eachComponent( + components, + (component, compPath, componentComponents, compParent) => { + const row = getContextualRowData(component, compPath, data); + if (fn(component, data, row, compPath, componentComponents, index, compParent) === true) { + return true; + } + if (isComponentNestedDataType(component)) { + const value = get(data, compPath, data) as DataObject; + if (Array.isArray(value)) { + for (let i = 0; i < value.length; i++) { + const nestedComponentPath = + getModelType(component) === 'nestedDataArray' + ? `${compPath}[${i}].data` + : `${compPath}[${i}]`; + eachComponentData( + component.components, + data, + fn, + nestedComponentPath, + i, + component, + includeAll, + ); + } + return true; + } else if (isEmpty(row) && !includeAll) { + // Tree components may submit empty objects; since we've already evaluated the parent tree/layout component, we won't worry about constituent elements return true; } - if (isComponentNestedDataType(component)) { - const value = get(data, compPath, data) as DataObject; - if (Array.isArray(value)) { - for (let i = 0; i < value.length; i++) { - const nestedComponentPath = getModelType(component) === 'nestedDataArray' ? `${compPath}[${i}].data` : `${compPath}[${i}]`; - eachComponentData(component.components, data, fn, nestedComponentPath, i, component, includeAll); - } - return true; - } else if (isEmpty(row) && !includeAll) { - // Tree components may submit empty objects; since we've already evaluated the parent tree/layout component, we won't worry about constituent elements - return true; - } - if (getModelType(component) === 'dataObject') { - // No need to bother processing all the children data if there is no data for this form or the reference value has not been loaded. - const nestedFormValue: any = get(data, component.path); - const noReferenceAttached = nestedFormValue?._id && isEmpty(nestedFormValue.data) && !has(nestedFormValue, 'form'); - const shouldProcessNestedFormData = nestedFormValue?._id ? !noReferenceAttached : has(data, component.path); - if (shouldProcessNestedFormData) { - // For nested forms, we need to reset the "data" and "path" objects for all of the children components, and then re-establish the data when it is done. - const childPath: string = componentDataPath(component, path, compPath); - const childData: any = get(data, childPath, {}); - eachComponentData(component.components, childData, fn, '', index, component, includeAll); - set(data, childPath, childData); - } + if (getModelType(component) === 'dataObject') { + // No need to bother processing all the children data if there is no data for this form or the reference value has not been loaded. + const nestedFormValue: any = get(data, component.path); + const noReferenceAttached = + nestedFormValue?._id && isEmpty(nestedFormValue.data) && !has(nestedFormValue, 'form'); + const shouldProcessNestedFormData = nestedFormValue?._id + ? !noReferenceAttached + : has(data, component.path); + if (shouldProcessNestedFormData) { + // For nested forms, we need to reset the "data" and "path" objects for all of the children components, and then re-establish the data when it is done. + const childPath: string = componentDataPath(component, path, compPath); + const childData: any = get(data, childPath, {}); + eachComponentData( + component.components, + childData, + fn, + '', + index, + component, + includeAll, + ); + set(data, childPath, childData); } - else { - eachComponentData(component.components, data, fn, componentDataPath(component, path, compPath), index, component, includeAll); - } - return true; - } else if (getModelType(component) === 'none') { - const info = componentInfo(component); - if (info.hasColumns) { - const columnsComponent = component as HasColumns; - columnsComponent.columns.forEach((column: any) => - eachComponentData( - column.components, - data, - fn, - componentFormPath(columnsComponent, path, columnsComponent.path), - index, - component, - ) - ); - } else if (info.hasRows) { - const rowsComponent = component as HasRows; - rowsComponent.rows.forEach((row: any) => { - if (Array.isArray(row)) { - row.forEach((row) => - eachComponentData( - row.components, - data, - fn, - componentFormPath(rowsComponent, path, rowsComponent.path), - index, - component, - ) - ); - } - }); - } else if (info.hasComps) { - const componentWithChildren = component as HasChildComponents; + } else { + eachComponentData( + component.components, + data, + fn, + componentDataPath(component, path, compPath), + index, + component, + includeAll, + ); + } + return true; + } else if (getModelType(component) === 'none') { + const info = componentInfo(component); + if (info.hasColumns) { + const columnsComponent = component as HasColumns; + columnsComponent.columns.forEach((column: any) => + eachComponentData( + column.components, + data, + fn, + componentFormPath(columnsComponent, path, columnsComponent.path), + index, + component, + ), + ); + } else if (info.hasRows) { + const rowsComponent = component as HasRows; + rowsComponent.rows.forEach((row: any) => { + if (Array.isArray(row)) { + row.forEach((row) => eachComponentData( - componentWithChildren.components, + row.components, data, fn, - componentFormPath(componentWithChildren, path, componentWithChildren.path), + componentFormPath(rowsComponent, path, rowsComponent.path), index, - component - ); - } - return true; + component, + ), + ); + } + }); + } else if (info.hasComps) { + const componentWithChildren = component as HasChildComponents; + eachComponentData( + componentWithChildren.components, + data, + fn, + componentFormPath(componentWithChildren, path, componentWithChildren.path), + index, + component, + ); } - return false; - }, - true, - path, - parent, - ); - }; + return true; + } + return false; + }, + true, + path, + parent, + ); +}; diff --git a/src/utils/formUtil/eachComponentDataAsync.ts b/src/utils/formUtil/eachComponentDataAsync.ts index ae114acc..3889be0e 100644 --- a/src/utils/formUtil/eachComponentDataAsync.ts +++ b/src/utils/formUtil/eachComponentDataAsync.ts @@ -1,127 +1,136 @@ import { get, set, has, isEmpty } from 'lodash'; import { - Component, - DataObject, - EachComponentDataAsyncCallback, - HasChildComponents, - HasColumns, - HasRows + Component, + DataObject, + EachComponentDataAsyncCallback, + HasChildComponents, + HasColumns, + HasRows, } from 'types'; import { - getContextualRowData, - isComponentNestedDataType, - getModelType, - componentDataPath, - componentInfo, - componentFormPath + getContextualRowData, + isComponentNestedDataType, + getModelType, + componentDataPath, + componentInfo, + componentFormPath, } from './index'; import { eachComponentAsync } from './eachComponentAsync'; // Async each component data. export const eachComponentDataAsync = async ( - components: Component[], - data: DataObject, - fn: EachComponentDataAsyncCallback, - path = "", - index?: number, - parent?: Component, - includeAll: boolean = false, - ) => { - if (!components || !data) { - return; - } - return await eachComponentAsync( - components, - async (component: any, compPath: string, componentComponents: any, compParent: any) => { - const row = getContextualRowData(component, compPath, data); - if (await fn(component, data, row, compPath, componentComponents, index, compParent) === true) { + components: Component[], + data: DataObject, + fn: EachComponentDataAsyncCallback, + path = '', + index?: number, + parent?: Component, + includeAll: boolean = false, +) => { + if (!components || !data) { + return; + } + return await eachComponentAsync( + components, + async (component: any, compPath: string, componentComponents: any, compParent: any) => { + const row = getContextualRowData(component, compPath, data); + if ( + (await fn(component, data, row, compPath, componentComponents, index, compParent)) === true + ) { + return true; + } + if (isComponentNestedDataType(component)) { + const value = get(data, compPath, data); + if (Array.isArray(value)) { + for (let i = 0; i < value.length; i++) { + const nestedComponentPath = + getModelType(component) === 'nestedDataArray' + ? `${compPath}[${i}].data` + : `${compPath}[${i}]`; + await eachComponentDataAsync( + component.components, + data, + fn, + nestedComponentPath, + i, + component, + includeAll, + ); + } + return true; + } else if (isEmpty(row) && !includeAll) { + // Tree components may submit empty objects; since we've already evaluated the parent tree/layout component, we won't worry about constituent elements return true; } - if (isComponentNestedDataType(component)) { - const value = get(data, compPath, data); - if (Array.isArray(value)) { - for (let i = 0; i < value.length; i++) { - const nestedComponentPath = getModelType(component) === 'nestedDataArray' ? `${compPath}[${i}].data` : `${compPath}[${i}]`; - await eachComponentDataAsync( - component.components, - data, - fn, - nestedComponentPath, - i, - component, - includeAll, - ); - } - return true; - } else if (isEmpty(row) && !includeAll) { - // Tree components may submit empty objects; since we've already evaluated the parent tree/layout component, we won't worry about constituent elements - return true; + if (getModelType(component) === 'dataObject') { + // No need to bother processing all the children data if there is no data for this form or the reference value has not been loaded. + const nestedFormValue: any = get(data, component.path); + const noReferenceAttached = + nestedFormValue?._id && isEmpty(nestedFormValue.data) && !has(nestedFormValue, 'form'); + const shouldProcessNestedFormData = nestedFormValue?._id + ? !noReferenceAttached + : has(data, component.path); + if (shouldProcessNestedFormData) { + // For nested forms, we need to reset the "data" and "path" objects for all of the children components, and then re-establish the data when it is done. + const childPath: string = componentDataPath(component, path, compPath); + const childData: any = get(data, childPath, null); + await eachComponentDataAsync( + component.components, + childData, + fn, + '', + index, + component, + includeAll, + ); + set(data, childPath, childData); } - if (getModelType(component) === 'dataObject') { - // No need to bother processing all the children data if there is no data for this form or the reference value has not been loaded. - const nestedFormValue: any = get(data, component.path); - const noReferenceAttached = nestedFormValue?._id && isEmpty(nestedFormValue.data) && !has(nestedFormValue, 'form'); - const shouldProcessNestedFormData = nestedFormValue?._id ? !noReferenceAttached : has(data, component.path); - if (shouldProcessNestedFormData) { - // For nested forms, we need to reset the "data" and "path" objects for all of the children components, and then re-establish the data when it is done. - const childPath: string = componentDataPath(component, path, compPath); - const childData: any = get(data, childPath, null); - await eachComponentDataAsync(component.components, childData, fn, '', index, component, includeAll); - set(data, childPath, childData); - } + } else { + await eachComponentDataAsync( + component.components, + data, + fn, + componentDataPath(component, path, compPath), + index, + component, + includeAll, + ); + } + return true; + } else if (getModelType(component) === 'none') { + const info = componentInfo(component); + if (info.hasColumns) { + const columnsComponent = component as HasColumns; + for (const column of columnsComponent.columns) { + await eachComponentDataAsync(column.components, data, fn, path, index, component); } - else { - await eachComponentDataAsync(component.components, data, fn, componentDataPath(component, path, compPath), index, component, includeAll); + } else if (info.hasRows) { + const rowsComponent = component as HasRows; + for (const rowArray of rowsComponent.rows) { + if (Array.isArray(rowArray)) { + for (const row of rowArray) { + await eachComponentDataAsync(row.components, data, fn, path, index, component); + } + } } - return true; - } else if (getModelType(component) === 'none') { - const info = componentInfo(component); - if (info.hasColumns) { - const columnsComponent = component as HasColumns; - for (const column of columnsComponent.columns) { - await eachComponentDataAsync( - column.components, - data, - fn, - path, - index, - component, - ); - } - } else if (info.hasRows) { - const rowsComponent = component as HasRows; - for (const rowArray of rowsComponent.rows) { - if (Array.isArray(rowArray)) { - for (const row of rowArray) { - await eachComponentDataAsync( - row.components, - data, - fn, - path, - index, - component, - ) - } - } - } - } else if (info.hasComps) { - const componentWithChildren = component as HasChildComponents; - await eachComponentDataAsync( - componentWithChildren.components, - data, - fn, - componentFormPath(componentWithChildren, path, componentWithChildren.path), - index, - component - ); - } - return true; + } else if (info.hasComps) { + const componentWithChildren = component as HasChildComponents; + await eachComponentDataAsync( + componentWithChildren.components, + data, + fn, + componentFormPath(componentWithChildren, path, componentWithChildren.path), + index, + component, + ); } - return false; - }, - true, - path, - parent - ); - }; + return true; + } + return false; + }, + true, + path, + parent, + ); +}; diff --git a/src/utils/formUtil/index.ts b/src/utils/formUtil/index.ts index 2e81030e..7eae2d63 100644 --- a/src/utils/formUtil/index.ts +++ b/src/utils/formUtil/index.ts @@ -16,8 +16,8 @@ import { isEqual, trim, isBoolean, - omit -} from "lodash"; + omit, +} from 'lodash'; import { compare, applyPatch } from 'fast-json-patch'; import { @@ -38,12 +38,12 @@ import { JSONConditional, SimpleConditional, AddressComponent, -} from "types"; -import { Evaluator } from "../Evaluator"; -import { eachComponent } from "./eachComponent"; +} from 'types'; +import { Evaluator } from '../Evaluator'; +import { eachComponent } from './eachComponent'; import { eachComponentData } from './eachComponentData'; -import { eachComponentAsync } from "./eachComponentAsync"; -import { eachComponentDataAsync } from "./eachComponentDataAsync"; +import { eachComponentAsync } from './eachComponentAsync'; +import { eachComponentDataAsync } from './eachComponentDataAsync'; /** * Flatten the form components for data manipulation. @@ -56,25 +56,22 @@ import { eachComponentDataAsync } from "./eachComponentDataAsync"; * @returns {Object} * The flattened components map. */ -export function flattenComponents( - components: Component[], - includeAll: boolean = false -) { +export function flattenComponents(components: Component[], includeAll: boolean = false) { const flattened: any = {}; eachComponent( components, (component: any, path: string) => { flattened[path] = component; }, - includeAll + includeAll, ); return flattened; } export function guid() { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0; - const v = c === "x" ? r : (r & 0x3) | 0x8; + const v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); } @@ -87,14 +84,14 @@ export function guid() { * @returns {string} */ export function uniqueName(name: string, template?: string, evalContext?: any) { - template = template || "{{fileName}}-{{guid}}"; + template = template || '{{fileName}}-{{guid}}'; //include guid in template anyway, to prevent overwriting issue if filename matches existing file - if (!template.includes("{{guid}}")) { + if (!template.includes('{{guid}}')) { template = `${template}-{{guid}}`; } - const parts = name.split("."); - let fileName = parts.slice(0, parts.length - 1).join("."); - const extension = parts.length > 1 ? `.${last(parts)}` : ""; + const parts = name.split('.'); + let fileName = parts.slice(0, parts.length - 1).join('.'); + const extension = parts.length > 1 ? `.${last(parts)}` : ''; //allow only 100 characters from original name to avoid issues with filename length restrictions fileName = fileName.substr(0, 100); evalContext = Object.assign(evalContext || {}, { @@ -102,10 +99,10 @@ export function uniqueName(name: string, template?: string, evalContext?: any) { guid: guid(), }); //only letters, numbers, dots, dashes, underscores and spaces are allowed. Anything else will be replaced with dash - const uniqueName = `${Evaluator.interpolate( - template, - evalContext - )}${extension}`.replace(/[^0-9a-zA-Z.\-_ ]/g, "-"); + const uniqueName = `${Evaluator.interpolate(template, evalContext)}${extension}`.replace( + /[^0-9a-zA-Z.\-_ ]/g, + '-', + ); return uniqueName; } @@ -128,29 +125,12 @@ export function uniqueName(name: string, template?: string, evalContext?: any) { * */ export const MODEL_TYPES_OF_KNOWN_COMPONENTS = { - nestedArray: [ - 'datagrid', - 'editgrid', - 'datatable', - 'dynamicWizard', - ], - nestedDataArray: [ - 'tagpad', - ], - dataObject: [ - 'form' - ], - object: [ - 'container', - 'address', - ], - map: [ - 'datamap', - ], - content: [ - 'htmlelement', - 'content' - ], + nestedArray: ['datagrid', 'editgrid', 'datatable', 'dynamicWizard'], + nestedDataArray: ['tagpad'], + dataObject: ['form'], + object: ['container', 'address'], + map: ['datamap'], + content: ['htmlelement', 'content'], string: [ 'textfield', 'password', @@ -162,22 +142,9 @@ export const MODEL_TYPES_OF_KNOWN_COMPONENTS = { 'time', 'signature', ], - number: [ - 'number', - 'currency' - ], - boolean: [ - 'checkbox', - 'radio', - ], - none: [ - 'table', - 'well', - 'columns', - 'fieldset', - 'panel', - 'tabs' - ], + number: ['number', 'currency'], + boolean: ['checkbox', 'radio'], + none: ['table', 'well', 'columns', 'fieldset', 'panel', 'tabs'], any: [ 'survey', 'captcha', @@ -201,14 +168,16 @@ export function getModelType(component: Component): keyof typeof MODEL_TYPES_OF_ } // Otherwise, check for known component types. - for (const type of Object.keys(MODEL_TYPES_OF_KNOWN_COMPONENTS) as (keyof typeof MODEL_TYPES_OF_KNOWN_COMPONENTS)[]) { + for (const type of Object.keys( + MODEL_TYPES_OF_KNOWN_COMPONENTS, + ) as (keyof typeof MODEL_TYPES_OF_KNOWN_COMPONENTS)[]) { if (MODEL_TYPES_OF_KNOWN_COMPONENTS[type].includes(component.type)) { return type; } } // Otherwise check for components that assert no value. - if ((component.input === false)) { + if (component.input === false) { return 'none'; } @@ -217,7 +186,7 @@ export function getModelType(component: Component): keyof typeof MODEL_TYPES_OF_ } export function getComponentAbsolutePath(component: Component) { - let paths = [component.path]; + const paths = [component.path]; while (component.parent) { component = component.parent; // We only need to do this for nested forms because they reset the data contexts for the children. @@ -240,15 +209,18 @@ export function getComponentPath(component: Component, path: string) { if (path.match(new RegExp(`${key}$`))) { return path; } - return (getModelType(component) === 'none') ? `${path}.${key}` : path; + return getModelType(component) === 'none' ? `${path}.${key}` : path; } export function isComponentNestedDataType(component: any): component is HasChildComponents { - return component.tree || getModelType(component) === 'nestedArray' || + return ( + component.tree || + getModelType(component) === 'nestedArray' || getModelType(component) === 'nestedDataArray' || getModelType(component) === 'dataObject' || getModelType(component) === 'object' || - getModelType(component) === 'map'; + getModelType(component) === 'map' + ); } export function componentPath(component: Component, parentPath?: string): string { @@ -281,7 +253,7 @@ export const componentDataPath = (component: any, parentPath: string, path: stri return parentPath; } return path; -} +}; export const componentFormPath = (component: any, parentPath: string, path: string): string => { parentPath = component.parentPath || parentPath; @@ -293,7 +265,7 @@ export const componentFormPath = (component: any, parentPath: string, path: stri return path; } return parentPath; -} +}; export function getComponentKey(component: Component) { if ( @@ -307,7 +279,7 @@ export function getComponentKey(component: Component) { } export function getContextualRowPath(component: Component, path: string): string { - return path.replace(new RegExp(`\.?${getComponentKey(component)}$`), ''); + return path.replace(new RegExp(`.?${getComponentKey(component)}$`), ''); } export function getContextualRowData(component: Component, path: string, data: any): any { @@ -328,23 +300,32 @@ export function componentInfo(component: any) { hasComps, layout: hasColumns || hasRows || (hasComps && !isInput) || isLayout || isContent, iterable: hasColumns || hasRows || hasComps || isContent, - } + }; } // Provided components, data, and a key, this will return the components data. export function getComponentData(components: Component[], data: DataObject, path: string) { const compData: any = { component: null, data: null }; - eachComponentData(components, data, (component: Component, data: DataObject, row: any, compPath: string) => { - if (compPath === path) { - compData.component = component; - compData.data = row; - return true; - } - }); + eachComponentData( + components, + data, + (component: Component, data: DataObject, row: any, compPath: string) => { + if (compPath === path) { + compData.component = component; + compData.data = row; + return true; + } + }, + ); return compData; } -export function getComponentActualValue(component: Component, compPath: string, data: any, row: any) { +export function getComponentActualValue( + component: Component, + compPath: string, + data: any, + row: any, +) { // The compPath here will NOT contain the indexes for DataGrids and EditGrids. // // a[0].b[2].c[3].d @@ -395,9 +376,11 @@ export function getComponentActualValue(component: Component, compPath: string, */ export function isLayoutComponent(component: Component) { return Boolean( - ((component as ColumnsComponent).columns && Array.isArray((component as ColumnsComponent).columns)) || - ((component as TableComponent).rows && Array.isArray((component as TableComponent).rows)) || - ((component as HasChildComponents).components && Array.isArray((component as HasChildComponents).components)) + ((component as ColumnsComponent).columns && + Array.isArray((component as ColumnsComponent).columns)) || + ((component as TableComponent).rows && Array.isArray((component as TableComponent).rows)) || + ((component as HasChildComponents).components && + Array.isArray((component as HasChildComponents).components)), ); } @@ -410,12 +393,11 @@ export function isLayoutComponent(component: Component) { */ export function matchComponent(component: Component, query: any) { if (isString(query)) { - return (component.key === query) || (component.path === query); - } - else { + return component.key === query || component.path === query; + } else { let matches = false; forOwn(query, (value, key) => { - matches = (get(component, key) === value); + matches = get(component, key) === value; if (!matches) { return false; } @@ -435,15 +417,19 @@ export function matchComponent(component: Component, query: any) { export function getComponent( components: Component[], key: any, - includeAll: any = false -): (Component | undefined) { + includeAll: any = false, +): Component | undefined { let result; - eachComponent(components, (component: Component, path: any) => { - if ((path === key) || (component.path === key) || (component.input && (component.key === key))) { - result = component; - return true; - } - }, includeAll); + eachComponent( + components, + (component: Component, path: any) => { + if (path === key || component.path === key || (component.input && component.key === key)) { + result = component; + return true; + } + }, + includeAll, + ); return result; } @@ -456,11 +442,15 @@ export function getComponent( */ export function searchComponents(components: Component[], query: any): Component[] { const results: Component[] = []; - eachComponent(components, (component: any) => { - if (matchComponent(component, query)) { - results.push(component); - } - }, true); + eachComponent( + components, + (component: any) => { + if (matchComponent(component, query)) { + results.push(component); + } + }, + true, + ); return results; } @@ -475,7 +465,6 @@ export function findComponents(components: Component[], query: any): Component[] return searchComponents(components, query); } - /** * Remove a component by path. * @@ -483,9 +472,8 @@ export function findComponents(components: Component[], query: any): Component[] * @param path */ export function removeComponent(components: Component[], path: string) { - // Using _.unset() leave a null value. Use Array splice instead. - // @ts-ignore - var index = path.pop(); + // @ts-expect-error - I'm not sure why we're using `pop` here if it's a string + const index = path.pop(); if (path.length !== 0) { components = get(components, path); } @@ -501,12 +489,13 @@ export function removeComponent(components: Component[], path: string) { */ export function hasCondition(component: Component) { return Boolean( - (component.customConditional) || - (component.conditional && ( - (component.conditional as LegacyConditional).when || - (component.conditional as JSONConditional).json || - ((component.conditional as SimpleConditional).conjunction && isBoolean((component.conditional as SimpleConditional).show) && !isEmpty((component.conditional as SimpleConditional).conditions)) - )) + component.customConditional || + (component.conditional && + ((component.conditional as LegacyConditional).when || + (component.conditional as JSONConditional).json || + ((component.conditional as SimpleConditional).conjunction && + isBoolean((component.conditional as SimpleConditional).show) && + !isEmpty((component.conditional as SimpleConditional).conditions)))), ); } @@ -520,9 +509,7 @@ export function hasCondition(component: Component) { * Parsed value. */ export function parseFloatExt(value: any) { - return parseFloat(isString(value) - ? value.replace(/[^\de.+-]/gi, '') - : value); + return parseFloat(isString(value) ? value.replace(/[^\de.+-]/gi, '') : value); } /** @@ -541,14 +528,10 @@ export function formatAsCurrency(value: string) { return ''; } - const parts = round(parsedValue, 2) - .toString() - .split('.'); + const parts = round(parsedValue, 2).toString().split('.'); parts[0] = chunk(Array.from(parts[0]).reverse(), 3) .reverse() - .map((part) => part - .reverse() - .join('')) + .map((part) => part.reverse().join('')) .join(','); parts[1] = pad(parts[1], 2, '0'); return parts.join('.'); @@ -591,8 +574,7 @@ export function getValue(submission: any, key: string) { }); return value; - } - else { + } else { return null; } }; @@ -605,107 +587,125 @@ export function getValue(submission: any, key: string) { * @param form */ export function getStrings(form: any) { - const properties = ['label', 'title', 'legend', 'tooltip', 'description', 'placeholder', 'prefix', 'suffix', 'errorLabel', 'content', 'html']; + const properties = [ + 'label', + 'title', + 'legend', + 'tooltip', + 'description', + 'placeholder', + 'prefix', + 'suffix', + 'errorLabel', + 'content', + 'html', + ]; const strings: any = []; - eachComponent(form.components, (component: any) => { - properties.forEach(property => { - if (component.hasOwnProperty(property) && component[property]) { - strings.push({ - key: component.key, - type: component.type, - property, - string: component[property] + eachComponent( + form.components, + (component: any) => { + properties.forEach((property) => { + if (component.hasOwnProperty(property) && component[property]) { + strings.push({ + key: component.key, + type: component.type, + property, + string: component[property], + }); + } + }); + if ( + (!component.dataSrc || component.dataSrc === 'values') && + component.hasOwnProperty('values') && + Array.isArray(component.values) && + component.values.length + ) { + component.values.forEach((value: any, index: number) => { + strings.push({ + key: component.key, + property: `value[${index}].label`, + string: component.values[index].label, + }); }); } - }); - if ((!component.dataSrc || component.dataSrc === 'values') && component.hasOwnProperty('values') && Array.isArray(component.values) && component.values.length) { - component.values.forEach((value: any, index: number) => { - strings.push({ - key: component.key, - property: `value[${index}].label`, - string: component.values[index].label - }); - }); - } - // Hard coded values from Day component - if (component.type === 'day') { - [ - 'day', - 'month', - 'year', - 'Day', - 'Month', - 'Year', - 'january', - 'february', - 'march', - 'april', - 'may', - 'june', - 'july', - 'august', - 'september', - 'october', - 'november', - 'december' - ].forEach(string => { - strings.push({ - key: component.key, - property: 'day', - string, + // Hard coded values from Day component + if (component.type === 'day') { + [ + 'day', + 'month', + 'year', + 'Day', + 'Month', + 'Year', + 'january', + 'february', + 'march', + 'april', + 'may', + 'june', + 'july', + 'august', + 'september', + 'october', + 'november', + 'december', + ].forEach((string) => { + strings.push({ + key: component.key, + property: 'day', + string, + }); }); - }); - if (component.fields.day.placeholder) { - strings.push({ - key: component.key, - property: 'fields.day.placeholder', - string: component.fields.day.placeholder, - }); - } + if (component.fields.day.placeholder) { + strings.push({ + key: component.key, + property: 'fields.day.placeholder', + string: component.fields.day.placeholder, + }); + } - if (component.fields.month.placeholder) { - strings.push({ - key: component.key, - property: 'fields.month.placeholder', - string: component.fields.month.placeholder, - }); - } + if (component.fields.month.placeholder) { + strings.push({ + key: component.key, + property: 'fields.month.placeholder', + string: component.fields.month.placeholder, + }); + } - if (component.fields.year.placeholder) { - strings.push({ - key: component.key, - property: 'fields.year.placeholder', - string: component.fields.year.placeholder, - }); + if (component.fields.year.placeholder) { + strings.push({ + key: component.key, + property: 'fields.year.placeholder', + string: component.fields.year.placeholder, + }); + } } - } - if (component.type === 'editgrid') { - const string = component.addAnother || 'Add Another'; - if (component.addAnother) { - strings.push({ - key: component.key, - property: 'addAnother', - string, - }); + if (component.type === 'editgrid') { + const string = component.addAnother || 'Add Another'; + if (component.addAnother) { + strings.push({ + key: component.key, + property: 'addAnother', + string, + }); + } } - } - if (component.type === 'select') { - [ - 'loading...', - 'Type to search' - ].forEach(string => { - strings.push({ - key: component.key, - property: 'select', - string, + if (component.type === 'select') { + ['loading...', 'Type to search'].forEach((string) => { + strings.push({ + key: component.key, + property: 'select', + string, + }); }); - }); - } - }, true); + } + }, + true, + ); return strings; } @@ -723,14 +723,14 @@ export function generateFormChange(type: any, data: any) { container: data.parent.key, // Parent component path: data.path, // Path to container within parent component. index: data.index, // Index of component in parent container. - component: data.component + component: data.component, }; break; case 'edit': change = { op: 'edit', key: data.originalComponent.key, - patches: compare(data.originalComponent, data.component) + patches: compare(data.originalComponent, data.component), }; // Don't save if nothing changed. @@ -752,10 +752,10 @@ export function generateFormChange(type: any, data: any) { export function applyFormChanges(form: any, changes: any) { const failed: any = []; changes.forEach(function (change: any) { - var found = false; + let found = false; switch (change.op) { - case 'add': - var newComponent = change.component; + case 'add': { + let newComponent = change.component; // Find the container to set the component in. findComponent(form.components, change.container, null, function (parent: any) { @@ -771,10 +771,11 @@ export function applyFormChanges(form: any, changes: any) { }); found = true; - var container = get(parent, change.path); + const container = get(parent, change.path); container.splice(change.index, 0, newComponent); }); break; + } case 'remove': findComponent(form.components, change.key, null, function (component: any, path: any) { found = true; @@ -797,8 +798,7 @@ export function applyFormChanges(form: any, changes: any) { } set(form.components, path, newComponent); - } - catch (err) { + } catch (ignoreErr) { failed.push(change); } }); @@ -813,22 +813,22 @@ export function applyFormChanges(form: any, changes: any) { return { form, - failed + failed, }; } /** -* This function will find a component in a form and return the component AND THE PATH to the component in the form. -* Path to the component is stored as an array of nested components and their indexes.The Path is being filled recursively -* when you iterating through the nested structure. -* If the component is not found the callback won't be called and function won't return anything. -* -* @param components -* @param key -* @param fn -* @param path -* @returns {*} -*/ + * This function will find a component in a form and return the component AND THE PATH to the component in the form. + * Path to the component is stored as an array of nested components and their indexes.The Path is being filled recursively + * when you iterating through the nested structure. + * If the component is not found the callback won't be called and function won't return anything. + * + * @param components + * @param key + * @param fn + * @param path + * @returns {*} + */ export function findComponent(components: any, key: any, path: any, fn: any) { if (!components) return; path = path || []; @@ -838,7 +838,7 @@ export function findComponent(components: any, key: any, path: any, fn: any) { } components.forEach(function (component: any, index: any) { - var newPath = path.slice(); + const newPath = path.slice(); // Add an index of the component it iterates through in nested structure newPath.push(index); if (!component) return; @@ -846,7 +846,7 @@ export function findComponent(components: any, key: any, path: any, fn: any) { if (component.hasOwnProperty('columns') && Array.isArray(component.columns)) { newPath.push('columns'); component.columns.forEach(function (column: any, index: any) { - var colPath = newPath.slice(); + const colPath = newPath.slice(); colPath.push(index); colPath.push('components'); findComponent(column.components, key, colPath, fn); @@ -856,10 +856,10 @@ export function findComponent(components: any, key: any, path: any, fn: any) { if (component.hasOwnProperty('rows') && Array.isArray(component.rows)) { newPath.push('rows'); component.rows.forEach(function (row: any, index: any) { - var rowPath = newPath.slice(); + const rowPath = newPath.slice(); rowPath.push(index); row.forEach(function (column: any, index: any) { - var colPath = rowPath.slice(); + const colPath = rowPath.slice(); colPath.push(index); colPath.push('components'); findComponent(column.components, key, colPath, fn); @@ -879,16 +879,26 @@ export function findComponent(components: any, key: any, path: any, fn: any) { }); } -const isCheckboxComponent = (component: any): component is CheckboxComponent => component?.type === 'checkbox'; -const isDataGridComponent = (component: any): component is DataGridComponent => component?.type === 'datagrid'; -const isEditGridComponent = (component: any): component is EditGridComponent => component?.type === 'editgrid'; -const isAddressComponent = (component: any): component is AddressComponent => component?.type === 'address'; -const isDataTableComponent = (component: any): component is DataTableComponent => component?.type === 'datatable'; -const hasChildComponents = (component: any): component is HasChildComponents => component?.components != null; -const isDateTimeComponent = (component: any): component is DateTimeComponent => component?.type === 'datetime'; -const isSelectBoxesComponent = (component: any): component is SelectBoxesComponent => component?.type === 'selectboxes'; -const isTextAreaComponent = (component: any): component is TextAreaComponent => component?.type === 'textarea'; -const isTextFieldComponent = (component: any): component is TextFieldComponent => component?.type === 'textfield'; +const isCheckboxComponent = (component: any): component is CheckboxComponent => + component?.type === 'checkbox'; +const isDataGridComponent = (component: any): component is DataGridComponent => + component?.type === 'datagrid'; +const isEditGridComponent = (component: any): component is EditGridComponent => + component?.type === 'editgrid'; +const isAddressComponent = (component: any): component is AddressComponent => + component?.type === 'address'; +const isDataTableComponent = (component: any): component is DataTableComponent => + component?.type === 'datatable'; +const hasChildComponents = (component: any): component is HasChildComponents => + component?.components != null; +const isDateTimeComponent = (component: any): component is DateTimeComponent => + component?.type === 'datetime'; +const isSelectBoxesComponent = (component: any): component is SelectBoxesComponent => + component?.type === 'selectboxes'; +const isTextAreaComponent = (component: any): component is TextAreaComponent => + component?.type === 'textarea'; +const isTextFieldComponent = (component: any): component is TextFieldComponent => + component?.type === 'textfield'; export function getEmptyValue(component: Component) { switch (component.type) { @@ -922,36 +932,46 @@ function trimBlanks(value: unknown) { if (Array.isArray(value)) { value = value.map((val: any) => replaceBlanks(val)); - } - else { + } else { value = replaceBlanks(value); } return value; } function isValueEmpty(component: Component, value: any) { - const compValueIsEmptyArray = (isArray(value) && value.length === 1) ? isEqual(value[0], getEmptyValue(component)) : false; - return value == null || value === '' || (isArray(value) && value.length === 0) || compValueIsEmptyArray; + const compValueIsEmptyArray = + isArray(value) && value.length === 1 ? isEqual(value[0], getEmptyValue(component)) : false; + return ( + value == null || value === '' || (isArray(value) && value.length === 0) || compValueIsEmptyArray + ); } -export function isComponentDataEmpty(component: Component, data: any, path: string, valueCond?:any): boolean { - const value = isNil(valueCond) ? get(data, path): valueCond; +export function isComponentDataEmpty( + component: Component, + data: any, + path: string, + valueCond?: any, +): boolean { + const value = isNil(valueCond) ? get(data, path) : valueCond; const addressIgnoreProperties = ['mode', 'address']; if (isCheckboxComponent(component)) { return isValueEmpty(component, value) || value === false; - } - else if (isAddressComponent(component)) { - if(Object.keys(value).length === 0) { - return true + } else if (isAddressComponent(component)) { + if (Object.keys(value).length === 0) { + return true; } return !Object.values(omit(value, addressIgnoreProperties)).some(Boolean); - } - else if (isDataGridComponent(component) || isEditGridComponent(component) || isDataTableComponent(component) || hasChildComponents(component)) { + } else if ( + isDataGridComponent(component) || + isEditGridComponent(component) || + isDataTableComponent(component) || + hasChildComponents(component) + ) { if (component.components?.length) { let childrenEmpty = true; // wrap component in an array to let eachComponentData handle introspection to child components (e.g. this will be different // for data grids versus nested forms, etc.) - eachComponentData([component], data, (thisComponent, data, row, path, components, index) => { + eachComponentData([component], data, (thisComponent, data, row, path) => { if (component.key === thisComponent.key) return; if (!isComponentDataEmpty(thisComponent, data, path)) { childrenEmpty = false; @@ -973,10 +993,17 @@ export function isComponentDataEmpty(component: Component, data: any, path: stri return isValueEmpty(component, value) || selectBoxEmpty; } else if (isTextAreaComponent(component)) { const isPlain = !component.wysiwyg && !component.editor; - return isPlain ? typeof value === 'string' ? isValueEmpty(component, value.trim()) : isValueEmpty(component, value) : isValueEmpty(component, trimBlanks(value)); + return isPlain + ? typeof value === 'string' + ? isValueEmpty(component, value.trim()) + : isValueEmpty(component, value) + : isValueEmpty(component, trimBlanks(value)); } else if (isTextFieldComponent(component)) { if (component.allowMultipleMasks && !!component.inputMasks && !!component.inputMasks.length) { - return isValueEmpty(component, value) || (component.multiple ? value.length === 0 : (!value.maskName || !value.value)); + return ( + isValueEmpty(component, value) || + (component.multiple ? value.length === 0 : !value.maskName || !value.value) + ); } return isValueEmpty(component, value?.toString().trim()); } diff --git a/src/utils/jwtDecode.ts b/src/utils/jwtDecode.ts index 67c97e67..a8da5a44 100644 --- a/src/utils/jwtDecode.ts +++ b/src/utils/jwtDecode.ts @@ -1,72 +1,64 @@ // copied from https://github.com/auth0/jwt-decode function b64DecodeUnicode(str: string) { - return decodeURIComponent( - atob(str).replace(/(.)/g, function (m, p) { - let code = p.charCodeAt(0).toString(16).toUpperCase(); - if (code.length < 2) { - code = '0' + code; - } - return '%' + code; - }) - ); + return decodeURIComponent( + atob(str).replace(/(.)/g, function (m, p) { + let code = p.charCodeAt(0).toString(16).toUpperCase(); + if (code.length < 2) { + code = '0' + code; + } + return '%' + code; + }), + ); } function b64UrlDecode(str: string) { - let output = str.replace(/-/g, '+').replace(/_/g, '/'); - switch (output.length % 4) { - case 0: - break; - case 2: - output += '=='; - break; - case 3: - output += '='; - break; - default: - throw new Error('base64 string is not of the correct length'); - } + let output = str.replace(/-/g, '+').replace(/_/g, '/'); + switch (output.length % 4) { + case 0: + break; + case 2: + output += '=='; + break; + case 3: + output += '='; + break; + default: + throw new Error('base64 string is not of the correct length'); + } - try { - return b64DecodeUnicode(output); - } catch (err) { - return atob(output); - } + try { + return b64DecodeUnicode(output); + } catch (ignoreErr) { + return atob(output); + } } export function jwtDecode(token: string, options: { header?: boolean } = {}) { - if (typeof token !== 'string') { - throw new Error('Invalid token specified: must be a string'); - } + if (typeof token !== 'string') { + throw new Error('Invalid token specified: must be a string'); + } - const pos = options.header === true ? 0 : 1; + const pos = options.header === true ? 0 : 1; - const part = token.split('.')[pos]; - if (typeof part !== 'string') { - throw new Error('Invalid token specified: missing part #' + (pos + 1)); - } - let decoded; - try { - decoded = b64UrlDecode(part); - } catch (e: any) { - throw new Error( - 'Invalid token specified: invalid base64 for part #' + - (pos + 1) + - ' (' + - e.message + - ')' - ); - } + const part = token.split('.')[pos]; + if (typeof part !== 'string') { + throw new Error('Invalid token specified: missing part #' + (pos + 1)); + } + let decoded; + try { + decoded = b64UrlDecode(part); + } catch (e: any) { + throw new Error( + 'Invalid token specified: invalid base64 for part #' + (pos + 1) + ' (' + e.message + ')', + ); + } - try { - return JSON.parse(decoded); - } catch (e: any) { - throw new Error( - 'Invalid token specified: invalid json for part #' + - (pos + 1) + - ' (' + - e.message + - ')' - ); - } + try { + return JSON.parse(decoded); + } catch (e: any) { + throw new Error( + 'Invalid token specified: invalid json for part #' + (pos + 1) + ' (' + e.message + ')', + ); + } } diff --git a/src/utils/logic.ts b/src/utils/logic.ts index 42f86f21..b8a7360f 100644 --- a/src/utils/logic.ts +++ b/src/utils/logic.ts @@ -1,171 +1,206 @@ -import { Component, ConditionsScope, LogicContext, ProcessorContext } from "types"; -import { checkCustomConditional, checkJsonConditional, checkLegacyConditional, checkSimpleConditional, conditionallyHidden, isLegacyConditional } from "./conditions"; -import { LogicActionCustomAction, LogicActionMergeComponentSchema, LogicActionProperty, LogicActionPropertyBoolean, LogicActionPropertyString, LogicActionValue } from "types/AdvancedLogic"; +import { ConditionsScope, LogicContext, ProcessorContext } from 'types'; +import { + checkCustomConditional, + checkJsonConditional, + checkLegacyConditional, + checkSimpleConditional, + conditionallyHidden, + isLegacyConditional, +} from './conditions'; +import { + LogicActionCustomAction, + LogicActionMergeComponentSchema, + LogicActionProperty, + LogicActionPropertyBoolean, + LogicActionPropertyString, + LogicActionValue, +} from 'types/AdvancedLogic'; import { get, set, clone, isEqual, assign } from 'lodash'; import { evaluate, interpolate } from 'modules/jsonlogic'; -import { registerEphemeralState } from "./utils"; +import { registerEphemeralState } from './utils'; export const hasLogic = (context: LogicContext): boolean => { - const { component } = context; - const { logic } = component; - if (!logic || !logic.length) { - return false; - } - return true; + const { component } = context; + const { logic } = component; + if (!logic || !logic.length) { + return false; + } + return true; }; export const checkTrigger = (context: LogicContext, trigger: any): boolean => { - let shouldTrigger: boolean | null = false; - switch (trigger.type) { - case 'simple': - if (isLegacyConditional(trigger.simple)) { - shouldTrigger = checkLegacyConditional(trigger.simple, context as ProcessorContext); - } - else { - shouldTrigger = checkSimpleConditional(trigger.simple, context as ProcessorContext) - } - break; - case 'javascript': - shouldTrigger = checkCustomConditional(trigger.javascript, context as ProcessorContext, 'result'); - break; - case 'json': - shouldTrigger = checkJsonConditional(trigger, context as ProcessorContext); - break; - default: - shouldTrigger = false; - break; - } - if (shouldTrigger === null) { - return false; - } - return shouldTrigger; + let shouldTrigger: boolean | null = false; + switch (trigger.type) { + case 'simple': + if (isLegacyConditional(trigger.simple)) { + shouldTrigger = checkLegacyConditional( + trigger.simple, + context as ProcessorContext, + ); + } else { + shouldTrigger = checkSimpleConditional( + trigger.simple, + context as ProcessorContext, + ); + } + break; + case 'javascript': + shouldTrigger = checkCustomConditional( + trigger.javascript, + context as ProcessorContext, + 'result', + ); + break; + case 'json': + shouldTrigger = checkJsonConditional(trigger, context as ProcessorContext); + break; + default: + shouldTrigger = false; + break; + } + if (shouldTrigger === null) { + return false; + } + return shouldTrigger; }; -export function setActionBooleanProperty(context: LogicContext, action: LogicActionPropertyBoolean): boolean { - const { component, scope, path } = context; - const property = action.property.value; - const currentValue = get(component, property, false).toString(); - const newValue = action.state.toString(); - if (currentValue !== newValue) { - set(component, property, newValue === 'true'); +export function setActionBooleanProperty( + context: LogicContext, + action: LogicActionPropertyBoolean, +): boolean { + const { component, scope, path } = context; + const property = action.property.value; + const currentValue = get(component, property, false).toString(); + const newValue = action.state.toString(); + if (currentValue !== newValue) { + set(component, property, newValue === 'true'); - // If this is "logic" forcing a component to set hidden property, then we will set the "conditionallyHidden" - // flag which will trigger the clearOnHide functionality. - if ( - property === 'hidden' && - path - ) { - if (!(scope as ConditionsScope).conditionals) { - (scope as ConditionsScope).conditionals = []; - } - const conditionallyHidden = (scope as ConditionsScope).conditionals?.find((cond: any) => { - return cond.path === path - }); - if (conditionallyHidden) { - conditionallyHidden.conditionallyHidden = !!component.hidden; - registerEphemeralState(component, 'conditionallyHidden', !!component.hidden); - } - else { - (scope as ConditionsScope).conditionals?.push({ - path, - conditionallyHidden: !!component.hidden, - }); - } - } - return true; + // If this is "logic" forcing a component to set hidden property, then we will set the "conditionallyHidden" + // flag which will trigger the clearOnHide functionality. + if (property === 'hidden' && path) { + if (!(scope as ConditionsScope).conditionals) { + (scope as ConditionsScope).conditionals = []; + } + const conditionallyHidden = (scope as ConditionsScope).conditionals?.find((cond: any) => { + return cond.path === path; + }); + if (conditionallyHidden) { + conditionallyHidden.conditionallyHidden = !!component.hidden; + registerEphemeralState(component, 'conditionallyHidden', !!component.hidden); + } else { + (scope as ConditionsScope).conditionals?.push({ + path, + conditionallyHidden: !!component.hidden, + }); + } } - return false; + return true; + } + return false; } -export function setActionStringProperty(context: LogicContext, action: LogicActionPropertyString): boolean { - const { component } = context; - const property = action.property.value; - const textValue = action.property.component ? (action as any)[action.property.component] : action.text; - const currentValue = get(component, property, ''); - const newValue = interpolate({...context, value: ''}, textValue, (evalContext: any) => { - evalContext.value = currentValue; - }); - if (newValue !== currentValue) { - set(component, property, newValue); - return true; - } - return false; +export function setActionStringProperty( + context: LogicContext, + action: LogicActionPropertyString, +): boolean { + const { component } = context; + const property = action.property.value; + const textValue = action.property.component + ? (action as any)[action.property.component] + : action.text; + const currentValue = get(component, property, ''); + const newValue = interpolate({ ...context, value: '' }, textValue, (evalContext: any) => { + evalContext.value = currentValue; + }); + if (newValue !== currentValue) { + set(component, property, newValue); + return true; + } + return false; } export function setActionProperty(context: LogicContext, action: LogicActionProperty): boolean { - switch (action.property.type) { - case 'boolean': - return setActionBooleanProperty(context, action as LogicActionPropertyBoolean); - case 'string': - return setActionStringProperty(context, action as LogicActionPropertyString); - } - return false; + switch (action.property.type) { + case 'boolean': + return setActionBooleanProperty(context, action as LogicActionPropertyBoolean); + case 'string': + return setActionStringProperty(context, action as LogicActionPropertyString); + } + return false; } export function setValueProperty(context: LogicContext, action: LogicActionValue) { - const { component, data, value, path} = context; - const oldValue = get(data, path); - const newValue = evaluate(context, action.value, 'value', (evalContext: any) => { - evalContext.value = clone(oldValue); - }); - if ( - !isEqual(oldValue, newValue) && - !(component.clearOnHide && conditionallyHidden(context as ProcessorContext)) - ) { - set(data, path, newValue); - return true; - } - return false; + const { component, data, path } = context; + const oldValue = get(data, path); + const newValue = evaluate(context, action.value, 'value', (evalContext: any) => { + evalContext.value = clone(oldValue); + }); + if ( + !isEqual(oldValue, newValue) && + !(component.clearOnHide && conditionallyHidden(context as ProcessorContext)) + ) { + set(data, path, newValue); + return true; + } + return false; } -export function setMergeComponentSchema(context: LogicContext, action: LogicActionMergeComponentSchema) { - const { component, data, path } = context; - const oldValue = get(data, path); - const schema = evaluate({...context, value: {}}, action.schemaDefinition, 'schema', (evalContext: any) => { - evalContext.value = clone(oldValue); - }); - const merged = assign({}, component, schema); - if (!isEqual(component, merged)) { - assign(component, schema); - return true; - } - return false; +export function setMergeComponentSchema( + context: LogicContext, + action: LogicActionMergeComponentSchema, +) { + const { component, data, path } = context; + const oldValue = get(data, path); + const schema = evaluate( + { ...context, value: {} }, + action.schemaDefinition, + 'schema', + (evalContext: any) => { + evalContext.value = clone(oldValue); + }, + ); + const merged = assign({}, component, schema); + if (!isEqual(component, merged)) { + assign(component, schema); + return true; + } + return false; } export function setCustomAction(context: LogicContext, action: LogicActionCustomAction) { - return setValueProperty(context, { type: 'value', value: action.customAction }); + return setValueProperty(context, { type: 'value', value: action.customAction }); } export const applyActions = (context: LogicContext): boolean => { - const { component } = context; - const { logic } = component; - if (!logic || !logic.length) { - return false; + const { component } = context; + const { logic } = component; + if (!logic || !logic.length) { + return false; + } + return logic.reduce((changed, logicItem) => { + const { actions, trigger } = logicItem; + if (!trigger || !actions || !actions.length || !checkTrigger(context, trigger)) { + return changed; } - return logic.reduce((changed, logicItem) => { - const { actions, trigger } = logicItem; - if (!trigger || !actions || !actions.length || !checkTrigger(context, trigger)) { - return changed; - } - return actions.reduce((changed, action) => { - switch (action.type) { - case 'property': - if (setActionProperty(context, action)) { - return true; - } - return changed; - case 'value': - return setValueProperty(context, action) || changed; - case 'mergeComponentSchema': - if (setMergeComponentSchema(context, action)) { - return true; - } - return changed; - case 'customAction': - return setCustomAction(context, action) || changed; - default: - return changed; - } - }, changed); - }, false); + return actions.reduce((changed, action) => { + switch (action.type) { + case 'property': + if (setActionProperty(context, action)) { + return true; + } + return changed; + case 'value': + return setValueProperty(context, action) || changed; + case 'mergeComponentSchema': + if (setMergeComponentSchema(context, action)) { + return true; + } + return changed; + case 'customAction': + return setCustomAction(context, action) || changed; + default: + return changed; + } + }, changed); + }, false); }; diff --git a/src/utils/mask.ts b/src/utils/mask.ts index 0ae3cdeb..397d9123 100644 --- a/src/utils/mask.ts +++ b/src/utils/mask.ts @@ -1,4 +1,4 @@ -import { isRegExp } from 'lodash' +import { isRegExp } from 'lodash'; /** * Returns an input mask that is compatible with the input mask library. @@ -57,10 +57,10 @@ export function matchInputMask(value: any, inputMask: any) { const char = value[i]; const charPart = inputMask[i]; - if (!(isRegExp(charPart) && charPart.test(char) || charPart === char)) { + if (!((isRegExp(charPart) && charPart.test(char)) || charPart === char)) { return false; } } return true; -} \ No newline at end of file +} diff --git a/src/utils/operators/ConditionOperator.js b/src/utils/operators/ConditionOperator.js index 2e0c8550..420c5fc5 100644 --- a/src/utils/operators/ConditionOperator.js +++ b/src/utils/operators/ConditionOperator.js @@ -1,30 +1,29 @@ import { isArray, some } from 'lodash'; -/* eslint-disable no-unused-vars */ export default class ConditionOperator { - static get operatorKey() { - return ''; - } - - static get displayedName() { - return ''; - } + static get operatorKey() { + return ''; + } - static get requireValue() { - return true; - } + static get displayedName() { + return ''; + } - execute(options) { - return true; - } + static get requireValue() { + return true; + } - getResult(options = {}) { - const { value } = options; + execute() { + return true; + } - if (isArray(value)) { - return some(value, valueItem => this.execute({ ...options, value: valueItem })); - } + getResult(options = {}) { + const { value } = options; - return this.execute(options); + if (isArray(value)) { + return some(value, (valueItem) => this.execute({ ...options, value: valueItem })); } + + return this.execute(options); + } } diff --git a/src/utils/operators/DateGreaterThan.js b/src/utils/operators/DateGreaterThan.js index db0d82b9..7c00cd9b 100644 --- a/src/utils/operators/DateGreaterThan.js +++ b/src/utils/operators/DateGreaterThan.js @@ -2,41 +2,53 @@ import ConditionOperator from './ConditionOperator'; import moment from 'moment'; import { isPartialDay, getDateValidationFormat } from '../../utils/date'; export default class DateGeaterThan extends ConditionOperator { - static get operatorKey() { - return 'dateGreaterThan'; + static get operatorKey() { + return 'dateGreaterThan'; + } + + static get displayedName() { + return 'Greater Than'; + } + + getFormattedDates({ value, comparedValue, conditionTriggerComponent }) { + const validationFormat = + conditionTriggerComponent && conditionTriggerComponent.component.type === 'day' + ? getDateValidationFormat(conditionTriggerComponent.component) + : null; + const date = validationFormat ? moment(value, validationFormat) : moment(value); + const comparedDate = validationFormat + ? moment(comparedValue, validationFormat) + : moment(comparedValue); + + return { date, comparedDate }; + } + + execute(options, functionName = 'isAfter') { + const { value, instance, conditionComponentPath } = options; + + if (!value) { + return false; } - static get displayedName() { - return 'Greater Than'; - } - - getFormattedDates({ value, comparedValue, conditionTriggerComponent }) { - const validationFormat = conditionTriggerComponent && conditionTriggerComponent.component.type === 'day' ? getDateValidationFormat(conditionTriggerComponent.component) : null; - const date = validationFormat ? moment(value, validationFormat) : moment(value); - const comparedDate = validationFormat ? moment(comparedValue, validationFormat) : moment(comparedValue); + let conditionTriggerComponent = null; - return { date, comparedDate }; + if (instance && instance.root) { + conditionTriggerComponent = instance.root.getComponent(conditionComponentPath); } - execute(options, functionName = 'isAfter') { - const { value, instance, conditionComponentPath } = options; - - if (!value) { - return false; - } - - let conditionTriggerComponent = null; - - if (instance && instance.root) { - conditionTriggerComponent = instance.root.getComponent(conditionComponentPath); - } - - if (conditionTriggerComponent && conditionTriggerComponent.component.type === 'day' && isPartialDay(conditionTriggerComponent.component, value)) { - return false; - } + if ( + conditionTriggerComponent && + conditionTriggerComponent.component.type === 'day' && + isPartialDay(conditionTriggerComponent.component, value) + ) { + return false; + } - const { date, comparedDate } = this.getFormattedDates({ ...options, conditionTriggerComponent }); + const { date, comparedDate } = this.getFormattedDates({ + ...options, + conditionTriggerComponent, + }); - return date[functionName](comparedDate); - } + return date[functionName](comparedDate); + } } diff --git a/src/utils/operators/DateGreaterThanOrEqual.js b/src/utils/operators/DateGreaterThanOrEqual.js index 7edc595a..7c71f272 100644 --- a/src/utils/operators/DateGreaterThanOrEqual.js +++ b/src/utils/operators/DateGreaterThanOrEqual.js @@ -1,15 +1,15 @@ import DateGeaterThan from './DateGreaterThan'; export default class DateGreaterThanOrEqual extends DateGeaterThan { - static get operatorKey() { - return 'dateGreaterThanOrEqual'; - } + static get operatorKey() { + return 'dateGreaterThanOrEqual'; + } - static get displayedName() { - return 'Greater Than Or Equal To'; - } + static get displayedName() { + return 'Greater Than Or Equal To'; + } - execute(options) { - return super.execute(options, 'isSameOrAfter'); - } + execute(options) { + return super.execute(options, 'isSameOrAfter'); + } } diff --git a/src/utils/operators/DateLessThan.js b/src/utils/operators/DateLessThan.js index 93cad088..4fbfca20 100644 --- a/src/utils/operators/DateLessThan.js +++ b/src/utils/operators/DateLessThan.js @@ -1,15 +1,15 @@ import DateGeaterThan from './DateGreaterThan'; export default class DateLessThan extends DateGeaterThan { - static get operatorKey() { - return 'dateLessThan'; - } + static get operatorKey() { + return 'dateLessThan'; + } - static get displayedName() { - return 'Less Than'; - } + static get displayedName() { + return 'Less Than'; + } - execute(options) { - return super.execute(options, 'isBefore'); - } + execute(options) { + return super.execute(options, 'isBefore'); + } } diff --git a/src/utils/operators/DateLessThanOrEqual.js b/src/utils/operators/DateLessThanOrEqual.js index 0a4031e7..8cc3b20d 100644 --- a/src/utils/operators/DateLessThanOrEqual.js +++ b/src/utils/operators/DateLessThanOrEqual.js @@ -1,15 +1,15 @@ import DateGeaterThan from './DateGreaterThan'; export default class DateLessThanOrEqual extends DateGeaterThan { - static get operatorKey() { - return 'dateLessThanOrEqual'; - } + static get operatorKey() { + return 'dateLessThanOrEqual'; + } - static get displayedName() { - return 'Less Than Or Equal To'; - } + static get displayedName() { + return 'Less Than Or Equal To'; + } - execute(options) { - return super.execute(options, 'isSameOrBefore'); - } + execute(options) { + return super.execute(options, 'isSameOrBefore'); + } } diff --git a/src/utils/operators/EndsWith.js b/src/utils/operators/EndsWith.js index c3839771..20109700 100644 --- a/src/utils/operators/EndsWith.js +++ b/src/utils/operators/EndsWith.js @@ -2,15 +2,15 @@ import ConditionOperator from './ConditionOperator'; import { endsWith } from 'lodash'; export default class EndsWith extends ConditionOperator { - static get operatorKey() { - return 'endsWith'; - } + static get operatorKey() { + return 'endsWith'; + } - static get displayedName() { - return 'Ends With'; - } + static get displayedName() { + return 'Ends With'; + } - execute({ value, comparedValue }) { - return endsWith(value, comparedValue); - } + execute({ value, comparedValue }) { + return endsWith(value, comparedValue); + } } diff --git a/src/utils/operators/GreaterThan.js b/src/utils/operators/GreaterThan.js index c9b10771..23c15654 100644 --- a/src/utils/operators/GreaterThan.js +++ b/src/utils/operators/GreaterThan.js @@ -2,15 +2,15 @@ import ConditionOperator from './ConditionOperator'; import { isNumber } from 'lodash'; export default class GeaterThan extends ConditionOperator { - static get operatorKey() { - return 'greaterThan'; - } + static get operatorKey() { + return 'greaterThan'; + } - static get displayedName() { - return 'Greater Than'; - } + static get displayedName() { + return 'Greater Than'; + } - execute({ value, comparedValue }) { - return isNumber(value) && value > comparedValue; - } + execute({ value, comparedValue }) { + return isNumber(value) && value > comparedValue; + } } diff --git a/src/utils/operators/GreaterThanOrEqual.js b/src/utils/operators/GreaterThanOrEqual.js index c1a64fe4..2085847b 100644 --- a/src/utils/operators/GreaterThanOrEqual.js +++ b/src/utils/operators/GreaterThanOrEqual.js @@ -2,15 +2,15 @@ import ConditionOperator from './ConditionOperator'; import { isNumber, isEqual } from 'lodash'; export default class GreaterThanOrEqual extends ConditionOperator { - static get operatorKey() { - return 'greaterThanOrEqual'; - } + static get operatorKey() { + return 'greaterThanOrEqual'; + } - static get displayedName() { - return 'Greater Than Or Equal To'; - } + static get displayedName() { + return 'Greater Than Or Equal To'; + } - execute({ value, comparedValue }) { - return isNumber(value) && (value > comparedValue || isEqual(value, comparedValue)); - } + execute({ value, comparedValue }) { + return isNumber(value) && (value > comparedValue || isEqual(value, comparedValue)); + } } diff --git a/src/utils/operators/Includes.js b/src/utils/operators/Includes.js index 15e45d5d..a2881c0d 100644 --- a/src/utils/operators/Includes.js +++ b/src/utils/operators/Includes.js @@ -2,15 +2,15 @@ import ConditionOperator from './ConditionOperator'; import { includes } from 'lodash'; export default class Includes extends ConditionOperator { - static get operatorKey() { - return 'includes'; - } + static get operatorKey() { + return 'includes'; + } - static get displayedName() { - return 'Includes'; - } + static get displayedName() { + return 'Includes'; + } - execute({ value, comparedValue }) { - return includes(value, comparedValue); - } + execute({ value, comparedValue }) { + return includes(value, comparedValue); + } } diff --git a/src/utils/operators/IsDateEqual.js b/src/utils/operators/IsDateEqual.js index 78ff9897..88e1bd07 100644 --- a/src/utils/operators/IsDateEqual.js +++ b/src/utils/operators/IsDateEqual.js @@ -1,15 +1,15 @@ import DateGeaterThan from './DateGreaterThan'; export default class IsDateEqual extends DateGeaterThan { - static get operatorKey() { - return 'isDateEqual'; - } + static get operatorKey() { + return 'isDateEqual'; + } - static get displayedName() { - return 'Is Equal To'; - } + static get displayedName() { + return 'Is Equal To'; + } - execute(options) { - return super.execute(options, 'isSame'); - } + execute(options) { + return super.execute(options, 'isSame'); + } } diff --git a/src/utils/operators/IsEmptyValue.js b/src/utils/operators/IsEmptyValue.js index 63fad224..c52e9b8e 100644 --- a/src/utils/operators/IsEmptyValue.js +++ b/src/utils/operators/IsEmptyValue.js @@ -2,23 +2,23 @@ import { isComponentDataEmpty } from 'utils/formUtil'; import ConditionOperator from './ConditionOperator'; export default class IsEmptyValue extends ConditionOperator { - static get operatorKey() { - return 'isEmpty'; - } + static get operatorKey() { + return 'isEmpty'; + } - static get displayedName() { - return 'Is Empty'; - } + static get displayedName() { + return 'Is Empty'; + } - static get requireValue() { - return false; - } + static get requireValue() { + return false; + } - execute({ value, conditionComponentPath, data, conditionComponent}) { - return isComponentDataEmpty(conditionComponent, data, conditionComponentPath, value); - } + execute({ value, conditionComponentPath, data, conditionComponent }) { + return isComponentDataEmpty(conditionComponent, data, conditionComponentPath, value); + } - getResult(options) { - return this.execute(options); - } + getResult(options) { + return this.execute(options); + } } diff --git a/src/utils/operators/IsEqualTo.js b/src/utils/operators/IsEqualTo.js index 286b4fff..7ee1c61f 100644 --- a/src/utils/operators/IsEqualTo.js +++ b/src/utils/operators/IsEqualTo.js @@ -1,29 +1,34 @@ import ConditionOperator from './ConditionOperator'; -import { isString, isObject, isEqual, get } from 'lodash'; +import { isString, isEqual, get } from 'lodash'; export default class IsEqualTo extends ConditionOperator { - static get operatorKey() { - return 'isEqual'; - } + static get operatorKey() { + return 'isEqual'; + } - static get displayedName() { - return 'Is Equal To'; - } + static get displayedName() { + return 'Is Equal To'; + } - execute({ value, comparedValue, conditionComponent }) { - // special check for select boxes - if (conditionComponent?.type === 'selectboxes') { - return get(value, comparedValue, false); - } - - if (value && comparedValue && typeof value !== typeof comparedValue && isString(comparedValue)) { - try { - comparedValue = JSON.parse(comparedValue); - } - // eslint-disable-next-line no-empty - catch (e) {} - } + execute({ value, comparedValue, conditionComponent }) { + // special check for select boxes + if (conditionComponent?.type === 'selectboxes') { + return get(value, comparedValue, false); + } - return isEqual(value, comparedValue); + if ( + value && + comparedValue && + typeof value !== typeof comparedValue && + isString(comparedValue) + ) { + try { + comparedValue = JSON.parse(comparedValue); + } catch (ignoreErr) { + // do nothing + } } + + return isEqual(value, comparedValue); + } } diff --git a/src/utils/operators/IsNotDateEqual.js b/src/utils/operators/IsNotDateEqual.js index 28f0ab0d..5e7bbeeb 100644 --- a/src/utils/operators/IsNotDateEqual.js +++ b/src/utils/operators/IsNotDateEqual.js @@ -1,15 +1,15 @@ import DateGeaterThan from './DateGreaterThan'; export default class IsNotDateEqual extends DateGeaterThan { - static get operatorKey() { - return 'isNotDateEqual'; - } + static get operatorKey() { + return 'isNotDateEqual'; + } - static get displayedName() { - return 'Is Not Equal To'; - } + static get displayedName() { + return 'Is Not Equal To'; + } - execute(options) { - return !super.execute(options, 'isSame'); - } + execute(options) { + return !super.execute(options, 'isSame'); + } } diff --git a/src/utils/operators/IsNotEmptyValue.js b/src/utils/operators/IsNotEmptyValue.js index f0eafb0d..437bbb05 100644 --- a/src/utils/operators/IsNotEmptyValue.js +++ b/src/utils/operators/IsNotEmptyValue.js @@ -1,15 +1,15 @@ -import IsEmptyValue from './IsEmptyValue'; +import IsEmptyValue from './IsEmptyValue'; export default class IsNotEmptyValue extends IsEmptyValue { - static get operatorKey() { - return 'isNotEmpty'; - } + static get operatorKey() { + return 'isNotEmpty'; + } - static get displayedName() { - return 'Is Not Empty'; - } + static get displayedName() { + return 'Is Not Empty'; + } - getResult(options) { - return !super.getResult(options); - } + getResult(options) { + return !super.getResult(options); + } } diff --git a/src/utils/operators/IsNotEqualTo.js b/src/utils/operators/IsNotEqualTo.js index 1e0b8fb5..00b229f5 100644 --- a/src/utils/operators/IsNotEqualTo.js +++ b/src/utils/operators/IsNotEqualTo.js @@ -2,15 +2,15 @@ import ConditionOperator from './ConditionOperator'; import { isEqual } from 'lodash'; export default class IsNotEqualTo extends ConditionOperator { - static get operatorKey() { - return 'isNotEqual'; - } + static get operatorKey() { + return 'isNotEqual'; + } - static get displayedName() { - return 'Is Not Equal To'; - } + static get displayedName() { + return 'Is Not Equal To'; + } - execute({ value, comparedValue }) { - return !isEqual(value, comparedValue); - } + execute({ value, comparedValue }) { + return !isEqual(value, comparedValue); + } } diff --git a/src/utils/operators/LessThan.js b/src/utils/operators/LessThan.js index 3ed3f804..902964ce 100644 --- a/src/utils/operators/LessThan.js +++ b/src/utils/operators/LessThan.js @@ -2,15 +2,15 @@ import ConditionOperator from './ConditionOperator'; import { isNumber } from 'lodash'; export default class LessThan extends ConditionOperator { - static get operatorKey() { - return 'lessThan'; - } + static get operatorKey() { + return 'lessThan'; + } - static get displayedName() { - return 'Less Than'; - } + static get displayedName() { + return 'Less Than'; + } - execute({ value, comparedValue }) { - return isNumber(value) && value < comparedValue; - } + execute({ value, comparedValue }) { + return isNumber(value) && value < comparedValue; + } } diff --git a/src/utils/operators/LessThanOrEqual.js b/src/utils/operators/LessThanOrEqual.js index 241c134e..9d742261 100644 --- a/src/utils/operators/LessThanOrEqual.js +++ b/src/utils/operators/LessThanOrEqual.js @@ -2,15 +2,15 @@ import ConditionOperator from './ConditionOperator'; import { isNumber, isEqual } from 'lodash'; export default class LessThanOrEqual extends ConditionOperator { - static get operatorKey() { - return 'lessThanOrEqual'; - } + static get operatorKey() { + return 'lessThanOrEqual'; + } - static get displayedName() { - return 'Less Than Or Equal To'; - } + static get displayedName() { + return 'Less Than Or Equal To'; + } - execute({ value, comparedValue }) { - return isNumber(value) && (value < comparedValue || isEqual(value, comparedValue)); - } + execute({ value, comparedValue }) { + return isNumber(value) && (value < comparedValue || isEqual(value, comparedValue)); + } } diff --git a/src/utils/operators/NotIncludes.js b/src/utils/operators/NotIncludes.js index 99a8ebcb..9ca8ca1e 100644 --- a/src/utils/operators/NotIncludes.js +++ b/src/utils/operators/NotIncludes.js @@ -1,15 +1,15 @@ import Includes from './Includes'; export default class NotIncludes extends Includes { - static get operatorKey() { - return 'notIncludes'; - } + static get operatorKey() { + return 'notIncludes'; + } - static get displayedName() { - return 'Not Includes'; - } + static get displayedName() { + return 'Not Includes'; + } - execute(options) { - return !super.execute(options); - } + execute(options) { + return !super.execute(options); + } } diff --git a/src/utils/operators/StartsWith.js b/src/utils/operators/StartsWith.js index 2a6e8412..50df6f63 100644 --- a/src/utils/operators/StartsWith.js +++ b/src/utils/operators/StartsWith.js @@ -2,15 +2,15 @@ import ConditionOperator from './ConditionOperator'; import { startsWith } from 'lodash'; export default class StartsWith extends ConditionOperator { - static get operatorKey() { - return 'startsWith'; - } + static get operatorKey() { + return 'startsWith'; + } - static get displayedName() { - return 'Starts With'; - } + static get displayedName() { + return 'Starts With'; + } - execute({ value, comparedValue }) { - return startsWith(value, comparedValue); - } + execute({ value, comparedValue }) { + return startsWith(value, comparedValue); + } } diff --git a/src/utils/operators/index.js b/src/utils/operators/index.js index d47ca848..0e02f180 100644 --- a/src/utils/operators/index.js +++ b/src/utils/operators/index.js @@ -35,7 +35,7 @@ const ConditionOperators = { [`${LessThanOrEqual.operatorKey}`]: LessThanOrEqual, [`${GreaterThanOrEqual.operatorKey}`]: GreaterThanOrEqual, [`${IsDateEqual.operatorKey}`]: IsDateEqual, - [`${IsNotDateEqual.operatorKey}`]: IsNotDateEqual + [`${IsNotDateEqual.operatorKey}`]: IsNotDateEqual, }; export default ConditionOperators; diff --git a/src/utils/override.ts b/src/utils/override.ts index 2824dbf5..4c67b136 100644 --- a/src/utils/override.ts +++ b/src/utils/override.ts @@ -4,21 +4,20 @@ * @param extenders */ export function override(classObj: any, extenders: any) { - for (let key in extenders) { - if (extenders.hasOwnProperty(key)) { - const extender = extenders[key]; - if (typeof extender === 'function') { - classObj.prototype[key] = extender; - } - else { - const prop: any = Object.getOwnPropertyDescriptor(classObj.prototype, key); - for (let attr in extender) { - if (extender.hasOwnProperty(attr)) { - prop[attr] = extender[attr](prop[attr]); - } - } - Object.defineProperty(classObj.prototype, key, prop); - } + for (const key in extenders) { + if (extenders.hasOwnProperty(key)) { + const extender = extenders[key]; + if (typeof extender === 'function') { + classObj.prototype[key] = extender; + } else { + const prop: any = Object.getOwnPropertyDescriptor(classObj.prototype, key); + for (const attr in extender) { + if (extender.hasOwnProperty(attr)) { + prop[attr] = extender[attr](prop[attr]); + } } + Object.defineProperty(classObj.prototype, key, prop); + } } -} \ No newline at end of file + } +} diff --git a/src/utils/sanitize.ts b/src/utils/sanitize.ts index c940f7cd..04f78a96 100644 --- a/src/utils/sanitize.ts +++ b/src/utils/sanitize.ts @@ -1,14 +1,14 @@ import createDOMPurify from 'dompurify'; let DOMPurify: any = null; const getDOMPurify = () => { - if (DOMPurify) { - return DOMPurify; - } - if (window) { - DOMPurify = createDOMPurify(window); - return DOMPurify; - } - return null; + if (DOMPurify) { + return DOMPurify; + } + if (window) { + DOMPurify = createDOMPurify(window); + return DOMPurify; + } + return null; }; /** @@ -17,42 +17,62 @@ const getDOMPurify = () => { * @param string * @returns {*} */ -export function sanitize(string: string, options: any): (TrustedHTML | string) { - const dompurify = getDOMPurify(); - if (!dompurify) { - console.log('DOMPurify unable to sanitize the contents.'); - return string; - } - // Dompurify configuration - const sanitizeOptions: any = { - ADD_ATTR: ['ref', 'target', 'within'], - USE_PROFILES: { html: true } - }; - // Add attrs - if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.addAttr) && options.sanitizeConfig.addAttr.length > 0) { - options.sanitizeConfig.addAttr.forEach((attr: any) => { - sanitizeOptions.ADD_ATTR.push(attr); - }); - } - // Add tags - if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.addTags) && options.sanitizeConfig.addTags.length > 0) { - sanitizeOptions.ADD_TAGS = options.sanitizeConfig.addTags; - } - // Allow tags - if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.allowedTags) && options.sanitizeConfig.allowedTags.length > 0) { - sanitizeOptions.ALLOWED_TAGS = options.sanitizeConfig.allowedTags; - } - // Allow attributes - if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.allowedAttrs) && options.sanitizeConfig.allowedAttrs.length > 0) { - sanitizeOptions.ALLOWED_ATTR = options.sanitizeConfig.allowedAttrs; - } - // Allowd URI Regex - if (options.sanitizeConfig && options.sanitizeConfig.allowedUriRegex) { - sanitizeOptions.ALLOWED_URI_REGEXP = options.sanitizeConfig.allowedUriRegex; - } - // Allow to extend the existing array of elements that are safe for URI-like values - if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.addUriSafeAttr) && options.sanitizeConfig.addUriSafeAttr.length > 0) { - sanitizeOptions.ADD_URI_SAFE_ATTR = options.sanitizeConfig.addUriSafeAttr; - } - return dompurify.sanitize(string, sanitizeOptions); - } \ No newline at end of file +export function sanitize(string: string, options: any): TrustedHTML | string { + const dompurify = getDOMPurify(); + if (!dompurify) { + console.log('DOMPurify unable to sanitize the contents.'); + return string; + } + // Dompurify configuration + const sanitizeOptions: any = { + ADD_ATTR: ['ref', 'target', 'within'], + USE_PROFILES: { html: true }, + }; + // Add attrs + if ( + options.sanitizeConfig && + Array.isArray(options.sanitizeConfig.addAttr) && + options.sanitizeConfig.addAttr.length > 0 + ) { + options.sanitizeConfig.addAttr.forEach((attr: any) => { + sanitizeOptions.ADD_ATTR.push(attr); + }); + } + // Add tags + if ( + options.sanitizeConfig && + Array.isArray(options.sanitizeConfig.addTags) && + options.sanitizeConfig.addTags.length > 0 + ) { + sanitizeOptions.ADD_TAGS = options.sanitizeConfig.addTags; + } + // Allow tags + if ( + options.sanitizeConfig && + Array.isArray(options.sanitizeConfig.allowedTags) && + options.sanitizeConfig.allowedTags.length > 0 + ) { + sanitizeOptions.ALLOWED_TAGS = options.sanitizeConfig.allowedTags; + } + // Allow attributes + if ( + options.sanitizeConfig && + Array.isArray(options.sanitizeConfig.allowedAttrs) && + options.sanitizeConfig.allowedAttrs.length > 0 + ) { + sanitizeOptions.ALLOWED_ATTR = options.sanitizeConfig.allowedAttrs; + } + // Allowd URI Regex + if (options.sanitizeConfig && options.sanitizeConfig.allowedUriRegex) { + sanitizeOptions.ALLOWED_URI_REGEXP = options.sanitizeConfig.allowedUriRegex; + } + // Allow to extend the existing array of elements that are safe for URI-like values + if ( + options.sanitizeConfig && + Array.isArray(options.sanitizeConfig.addUriSafeAttr) && + options.sanitizeConfig.addUriSafeAttr.length > 0 + ) { + sanitizeOptions.ADD_URI_SAFE_ATTR = options.sanitizeConfig.addUriSafeAttr; + } + return dompurify.sanitize(string, sanitizeOptions); +} diff --git a/src/utils/unwind.ts b/src/utils/unwind.ts index 1ca2a4ac..35497d95 100644 --- a/src/utils/unwind.ts +++ b/src/utils/unwind.ts @@ -2,155 +2,167 @@ import { get, set, has, each, find, filter } from 'lodash'; import { fastCloneDeep } from './fastCloneDeep'; import { eachComponent } from './formUtil'; export function mergeObject(src: any, dst: any) { - each(src, function (value: any, key: any) { - if (!Array.isArray(value)) { - dst[key] = value; - } - else { - if (!dst[key]) { - dst[key] = []; - } - mergeArray(value, dst[key]); - } - }); + each(src, function (value: any, key: any) { + if (!Array.isArray(value)) { + dst[key] = value; + } else { + if (!dst[key]) { + dst[key] = []; + } + mergeArray(value, dst[key]); + } + }); } export function mergeArray(src: any, dst: any) { - src.forEach(function (value: any) { - var query: any = {}; - each(value, function (subValue: any, key: any) { - if (!Array.isArray(subValue)) { - query[key] = subValue; - } - }); - var dstValue = find(dst, query); - if (dstValue) { - mergeObject(value, dstValue); - } - else { - dst.push(value); - } + src.forEach(function (value: any) { + const query: any = {}; + each(value, function (subValue: any, key: any) { + if (!Array.isArray(subValue)) { + query[key] = subValue; + } }); + const dstValue = find(dst, query); + if (dstValue) { + mergeObject(value, dstValue); + } else { + dst.push(value); + } + }); } export function rewind(submissions: any) { - var submission = { data: {} }; - if (submissions && submissions.length) { - submissions.forEach((sub: any) => mergeObject(sub.data, submission.data)); - } - return submission; + const submission = { data: {} }; + if (submissions && submissions.length) { + submissions.forEach((sub: any) => mergeObject(sub.data, submission.data)); + } + return submission; } export function unwind(form: any, submission: any) { - var dataPaths = {}; - var locked = {}; - var submissions = [fastCloneDeep(submission)]; - // Set the data value for a data path. - /* eslint-disable no-use-before-define */ - var setDataValue = function (dataPath: any, values: any, parent: any, offset: any, current: any) { - offset = offset || 0; - current = current || 0; - // Make sure we don't overwrite any locked values. - while (has(locked, "[" + current + "]." + parent)) { - if ((current + 1) >= submissions.length) { - submissions.push(fastCloneDeep(submissions[current])); - } - current++; - } - // Ensure that all parents have been copied over to this path. - /* eslint-disable no-useless-escape */ - var parentPath = parent.replace(/\.[^\.]+$/, ''); - if (!has(submissions[current].data, parentPath) && - submissions[current - 1] && - has(submissions[(current - 1)].data, parentPath)) { - set(submissions[current].data, parentPath, fastCloneDeep(get(submissions[(current - 1)].data, parentPath))); - } - /* eslint-enable no-useless-escape */ - var pathValue: any = []; - set(submissions[current].data, parent, pathValue); - set(locked, "[" + current + "]." + parent, true); - for (var i = offset; i < values.length; i++) { - if ((i - offset) <= dataPath.max) { - pathValue.push(values[i]); - if (dataPath.paths && Object.keys(dataPath.paths).length) { - addData(dataPath.paths, values[i], parent + "[" + (i - offset) + "]", current); - } - } - else { - setDataValue(dataPath, values, parent, i, current); - break; - } - } - }; - /* eslint-enable no-use-before-define */ - // Add data to a series of data paths. - var addData = function (dataPaths: any, data: any, parent?: any, current?: any) { - for (var path in dataPaths) { - var dataPath = dataPaths[path]; - if (data[path] && Array.isArray(data[path])) { - setDataValue(dataPath, data[path], (parent ? parent + "." + path : path), 0, current); - } - } - }; - var addDataPaths = function (dataPath: any, paths: any, index?: any, parentDataPath?: any) { - index = index || 0; - var path = paths[index]; - /* eslint-disable no-useless-escape */ - var matches = path.match(/([^\[]+)\[?([0-9]+)?\]?/); - /* eslint-enable no-useless-escape */ - if (matches && (matches.length === 3)) { - var dataParam = matches[1]; - var dataIndex = parseInt(matches[2], 10) || 0; - if (dataPath[dataParam]) { - if (dataIndex > dataPath[dataParam].max) { - dataPath[dataParam].max = dataIndex; - } - } - else { - dataPath[dataParam] = { - max: dataIndex, - param: dataParam, - parent: parentDataPath || null, - paths: {} - }; - } - if ((index + 1) < paths.length) { - addDataPaths(dataPath[dataParam].paths, paths, (index + 1), dataPath[dataParam]); - } - } - }; + const dataPaths = {}; + const locked = {}; + const submissions = [fastCloneDeep(submission)]; + // Set the data value for a data path. - // Iterate through all components. - eachComponent(form.components, function (component: any, path: any) { - if (component.type === 'form' && component.components?.length) { - eachComponent(component.components, (comp: any) => { - comp.isInsideNestedForm = true; - }); - } - if (!component.overlay || (!component.overlay.width && !component.overlay.height)) { - return; + const setDataValue = function ( + dataPath: any, + values: any, + parent: any, + offset: any, + current: any, + ) { + offset = offset || 0; + current = current || 0; + // Make sure we don't overwrite any locked values. + while (has(locked, '[' + current + '].' + parent)) { + if (current + 1 >= submissions.length) { + submissions.push(fastCloneDeep(submissions[current])); + } + current++; + } + // Ensure that all parents have been copied over to this path. + /* eslint-disable no-useless-escape */ + const parentPath = parent.replace(/\.[^\.]+$/, ''); + if ( + !has(submissions[current].data, parentPath) && + submissions[current - 1] && + has(submissions[current - 1].data, parentPath) + ) { + set( + submissions[current].data, + parentPath, + fastCloneDeep(get(submissions[current - 1].data, parentPath)), + ); + } + /* eslint-enable no-useless-escape */ + const pathValue: any = []; + set(submissions[current].data, parent, pathValue); + set(locked, '[' + current + '].' + parent, true); + for (let i = offset; i < values.length; i++) { + if (i - offset <= dataPath.max) { + pathValue.push(values[i]); + if (dataPath.paths && Object.keys(dataPath.paths).length) { + addData(dataPath.paths, values[i], parent + '[' + (i - offset) + ']', current); } + } else { + setDataValue(dataPath, values, parent, i, current); + break; + } + } + }; - var hasDataPath = component.properties && component.properties.dataPath; - var key = component.key; - if (hasDataPath) { - path = component.properties.dataPath; - key = component.properties.dataPath; - } - /* eslint-disable no-useless-escape */ - var paths = filter(path.replace(new RegExp(".?" + component.key + "$"), '').split('.')); - /* eslint-enable no-useless-escape */ - if (!hasDataPath && paths.length && !component.isInsideNestedForm) { - key = paths.join('.') + "." + component.key; - } - if (component.multiple) { - paths.push(component.key); - } - component.key = key; - if (paths && paths.length) { - addDataPaths(dataPaths, paths); + // Add data to a series of data paths. + const addData = function (dataPaths: any, data: any, parent?: any, current?: any) { + for (const path in dataPaths) { + const dataPath = dataPaths[path]; + if (data[path] && Array.isArray(data[path])) { + setDataValue(dataPath, data[path], parent ? parent + '.' + path : path, 0, current); + } + } + }; + const addDataPaths = function (dataPath: any, paths: any, index?: any, parentDataPath?: any) { + index = index || 0; + const path = paths[index]; + /* eslint-disable no-useless-escape */ + const matches = path.match(/([^\[]+)\[?([0-9]+)?\]?/); + /* eslint-enable no-useless-escape */ + if (matches && matches.length === 3) { + const dataParam = matches[1]; + const dataIndex = parseInt(matches[2], 10) || 0; + if (dataPath[dataParam]) { + if (dataIndex > dataPath[dataParam].max) { + dataPath[dataParam].max = dataIndex; } - }, true); - addData(dataPaths, submission.data); - return submissions; + } else { + dataPath[dataParam] = { + max: dataIndex, + param: dataParam, + parent: parentDataPath || null, + paths: {}, + }; + } + if (index + 1 < paths.length) { + addDataPaths(dataPath[dataParam].paths, paths, index + 1, dataPath[dataParam]); + } + } + }; + + // Iterate through all components. + eachComponent( + form.components, + function (component: any, path: any) { + if (component.type === 'form' && component.components?.length) { + eachComponent(component.components, (comp: any) => { + comp.isInsideNestedForm = true; + }); + } + if (!component.overlay || (!component.overlay.width && !component.overlay.height)) { + return; + } + + const hasDataPath = component.properties && component.properties.dataPath; + let key = component.key; + if (hasDataPath) { + path = component.properties.dataPath; + key = component.properties.dataPath; + } + + const paths = filter(path.replace(new RegExp('.?' + component.key + '$'), '').split('.')); + + if (!hasDataPath && paths.length && !component.isInsideNestedForm) { + key = paths.join('.') + '.' + component.key; + } + if (component.multiple) { + paths.push(component.key); + } + component.key = key; + if (paths && paths.length) { + addDataPaths(dataPaths, paths); + } + }, + true, + ); + addData(dataPaths, submission.data); + return submissions; } diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 0161d206..fd49f503 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -19,14 +19,12 @@ export function escapeRegExCharacters(value: string) { * @param value * @return {boolean} */ - export function boolValue(value: any) { +export function boolValue(value: any) { if (isBoolean(value)) { return value; - } - else if (isString(value)) { - return (value.toLowerCase() === 'true'); - } - else { + } else if (isString(value)) { + return value.toLowerCase() === 'true'; + } else { return !!value; } } @@ -45,20 +43,24 @@ export function unescapeHTML(str: string) { return doc.documentElement.textContent; } -export function registerEphemeralState(component: Component, name: keyof NonNullable, value: any) { +export function registerEphemeralState( + component: Component, + name: keyof NonNullable, + value: any, +) { if (!component.ephemeralState) { Object.defineProperty(component, 'ephemeralState', { enumerable: false, configurable: true, writable: true, - value: {} + value: {}, }); } Object.defineProperty(component.ephemeralState, name, { enumerable: false, writable: false, configurable: true, - value + value, }); } diff --git a/tsconfig.json b/tsconfig.json index 1ddbebda..955cf42e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,18 +4,18 @@ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ - "lib": ["es6", "dom"], /* Specify library files to be included in the compilation. */ - "allowJs": true, /* Allow javascript files to be compiled. */ + "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + "lib": ["es6", "dom"] /* Specify library files to be included in the compilation. */, + "allowJs": true /* Allow javascript files to be compiled. */, // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - "declaration": true, /* Generates corresponding '.d.ts' file. */ + "declaration": true /* Generates corresponding '.d.ts' file. */, // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ // "sourceMap": true, /* Generates corresponding '.map' file. */ // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "lib", /* Redirect output structure to the directory. */ - "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + "outDir": "lib" /* Redirect output structure to the directory. */, + "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, // "composite": true, /* Enable project compilation */ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ // "removeComments": true, /* Do not emit comments to output. */ @@ -25,13 +25,13 @@ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ + "strict": true /* Enable all strict type-checking options. */, // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - "noImplicitThis": false, /* Raise error on 'this' expressions with an implied 'any' type. */ + "noImplicitThis": false /* Raise error on 'this' expressions with an implied 'any' type. */, // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ /* Additional Checks */ @@ -42,13 +42,13 @@ /* Module Resolution Options */ // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + "baseUrl": "./" /* Base directory to resolve non-absolute module names. */, // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ @@ -59,12 +59,12 @@ // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ /* Experimental Options */ - "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ /* Advanced Options */ - "skipLibCheck": true, /* Skip type checking of declaration files. */ - "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */ + "skipLibCheck": true /* Skip type checking of declaration files. */, + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, "resolveJsonModule": true, "paths": { "base": ["src/experimental/base"], @@ -88,7 +88,7 @@ "process": ["src/process"], "process/*": ["src/process/*"], "template": ["src/experimental/template"], - "template/*": ["src/experimental/template/*"], + "template/*": ["src/experimental/template/*"] } }, "include": [ @@ -96,12 +96,8 @@ "src/*.ejs", "src/**/*.ts", "src/**/*.ejs", - "src/server/**/*.js" + "src/server/**/*.js", + "global.d.ts" ], - "exclude": [ - "node_modules", - "gulpfile.js", - "dist", - "**/*.spec.ts" - ] + "exclude": ["node_modules", "gulpfile.js", "dist", "**/*.spec.ts"] } diff --git a/types.d.ts b/types.d.ts index 3fa8628d..a8664ad5 100644 --- a/types.d.ts +++ b/types.d.ts @@ -1 +1 @@ -export * from './lib/types'; \ No newline at end of file +export * from './lib/types'; diff --git a/types.js b/types.js index e2c85f93..d4fb2702 100644 --- a/types.js +++ b/types.js @@ -1,17 +1,30 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __exportStar = (this && this.__exportStar) || function(m, exports) { - for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -__exportStar(require("./lib/types"), exports); \ No newline at end of file +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ('get' in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __exportStar = + (this && this.__exportStar) || + function (m, exports) { + for (var p in m) + if (p !== 'default' && !Object.prototype.hasOwnProperty.call(exports, p)) + __createBinding(exports, m, p); + }; +Object.defineProperty(exports, '__esModule', { value: true }); +__exportStar(require('./lib/types'), exports); diff --git a/yarn.lock b/yarn.lock index ad52440c..f98fa2af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -390,6 +390,64 @@ resolved "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0": + version "4.11.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== + +"@eslint/config-array@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.18.0.tgz#37d8fe656e0d5e3dbaea7758ea56540867fd074d" + integrity sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw== + dependencies: + "@eslint/object-schema" "^2.1.4" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.6.0.tgz#9930b5ba24c406d67a1760e94cdbac616a6eb674" + integrity sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg== + +"@eslint/eslintrc@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6" + integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@9.12.0", "@eslint/js@^9.12.0": + version "9.12.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.12.0.tgz#69ca3ca9fab9a808ec6d67b8f6edb156cbac91e1" + integrity sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA== + +"@eslint/object-schema@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843" + integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ== + +"@eslint/plugin-kit@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz#8712dccae365d24e9eeecb7b346f85e750ba343d" + integrity sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig== + dependencies: + levn "^0.4.1" + "@gulpjs/messages@^1.1.0": version "1.1.0" resolved "https://registry.npmjs.org/@gulpjs/messages/-/messages-1.1.0.tgz#94e70978ff676ade541faab459c37ae0c7095e5a" @@ -402,6 +460,29 @@ dependencies: is-negated-glob "^1.0.0" +"@humanfs/core@^0.19.0": + version "0.19.0" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.0.tgz#08db7a8c73bb07673d9ebd925f2dad746411fcec" + integrity sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw== + +"@humanfs/node@^0.16.5": + version "0.16.5" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.5.tgz#a9febb7e7ad2aff65890fdc630938f8d20aa84ba" + integrity sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg== + dependencies: + "@humanfs/core" "^0.19.0" + "@humanwhocodes/retry" "^0.3.0" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/retry@^0.3.0", "@humanwhocodes/retry@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -666,6 +747,11 @@ resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== +"@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + "@types/fetch-mock@^7.3.8": version "7.3.8" resolved "https://registry.npmjs.org/@types/fetch-mock/-/fetch-mock-7.3.8.tgz#2fd769cb7881ac029d06ab2c23a254a9f208a034" @@ -693,6 +779,11 @@ resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + "@types/lodash.template@^4.5.3": version "4.5.3" resolved "https://registry.npmjs.org/@types/lodash.template/-/lodash.template-4.5.3.tgz#1174483eaa761a76a9d68c4adbee4c4e2742f329" @@ -755,6 +846,87 @@ resolved "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz#7545ba4fc3c003d6c756f651f3bf163d8f0f29ba" integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA== +"@typescript-eslint/eslint-plugin@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz#9364b756d4d78bcbdf6fd3e9345e6924c68ad371" + integrity sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/type-utils" "8.8.1" + "@typescript-eslint/utils" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/parser@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.8.1.tgz#5952ba2a83bd52024b872f3fdc8ed2d3636073b8" + integrity sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow== + dependencies: + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/typescript-estree" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz#b4bea1c0785aaebfe3c4ab059edaea1c4977e7ff" + integrity sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA== + dependencies: + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + +"@typescript-eslint/type-utils@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz#31f59ec46e93a02b409fb4d406a368a59fad306e" + integrity sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA== + dependencies: + "@typescript-eslint/typescript-estree" "8.8.1" + "@typescript-eslint/utils" "8.8.1" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.8.1.tgz#ebe85e0fa4a8e32a24a56adadf060103bef13bd1" + integrity sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q== + +"@typescript-eslint/typescript-estree@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz#34649f4e28d32ee49152193bc7dedc0e78e5d1ec" + integrity sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg== + dependencies: + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.8.1.tgz#9e29480fbfa264c26946253daa72181f9f053c9d" + integrity sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/typescript-estree" "8.8.1" + +"@typescript-eslint/visitor-keys@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz#0fb1280f381149fc345dfde29f7542ff4e587fc5" + integrity sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag== + dependencies: + "@typescript-eslint/types" "8.8.1" + eslint-visitor-keys "^3.4.3" + "@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": version "1.12.1" resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" @@ -924,6 +1096,11 @@ acorn-import-assertions@^1.9.0: resolved "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + acorn-walk@^6.0.1: version "6.2.0" resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz" @@ -944,6 +1121,11 @@ acorn@^6.0.1: resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== +acorn@^8.12.0: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + acorn@^8.4.1: version "8.11.3" resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" @@ -974,7 +1156,7 @@ ajv-keywords@^3.5.2: resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.12.3, ajv@^6.12.5: +ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -996,6 +1178,13 @@ ansi-cyan@^0.1.1: dependencies: ansi-wrap "0.1.0" +ansi-escapes@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-7.0.0.tgz#00fc19f491bbb18e1d481b97868204f92109bfe7" + integrity sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw== + dependencies: + environment "^1.0.0" + ansi-red@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c" @@ -1008,6 +1197,11 @@ ansi-regex@^5.0.1: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + ansi-sequence-parser@^1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz#e0aa1cdcbc8f8bb0b5bca625aac41f5f056973cf" @@ -1027,6 +1221,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^6.0.0, ansi-styles@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + ansi-wrap@0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz" @@ -1237,6 +1436,13 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + browser-cookies@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/browser-cookies/-/browser-cookies-1.2.0.tgz" @@ -1300,6 +1506,11 @@ call-signature@0.0.2: resolved "https://registry.npmjs.org/call-signature/-/call-signature-0.0.2.tgz" integrity sha512-qvYvkAVcoae0obt8OsZn0VEBHeEpvYIZDy1gGYtZDJG0fHawew+Mi0dBjieFz8F8dzQ2Kr19+nsDm+T5XFVs+Q== +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -1347,7 +1558,7 @@ chalk@^2.0.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.1.0, chalk@^4.1.2: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1355,6 +1566,11 @@ chalk@^4.1.0, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + chance@^1.1.8: version "1.1.11" resolved "https://registry.npmjs.org/chance/-/chance-1.1.11.tgz" @@ -1392,6 +1608,21 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== +cli-cursor@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-5.0.0.tgz#24a4831ecf5a6b01ddeb32fb71a4b2088b0dce38" + integrity sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw== + dependencies: + restore-cursor "^5.0.0" + +cli-truncate@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-4.0.0.tgz#6cc28a2924fee9e25ce91e973db56c7066e6172a" + integrity sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA== + dependencies: + slice-ansi "^5.0.0" + string-width "^7.0.0" + cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -1453,7 +1684,7 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -colorette@^2.0.14: +colorette@^2.0.14, colorette@^2.0.20: version "2.0.20" resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== @@ -1480,6 +1711,11 @@ commander@^9.0.0: resolved "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== +commander@~12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -1543,7 +1779,7 @@ create-require@^1.1.0: resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^7.0.0, cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -1608,6 +1844,13 @@ debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: dependencies: ms "2.1.2" +debug@^4.3.2, debug@^4.3.4, debug@~4.3.6: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" @@ -1630,7 +1873,7 @@ deep-eql@^4.1.3: dependencies: type-detect "^4.0.0" -deep-is@~0.1.3: +deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.4" resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== @@ -1742,6 +1985,11 @@ electron-to-chromium@^1.4.668: resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.747.tgz#e37fa5b7b7e4c22607c5f59b5cf78f947266e77d" integrity sha512-+FnSWZIAvFHbsNVmUxhEqWiaOiPMcfum1GQzlWCg/wLigVtshOsjXHyEFfmt6cFK6+HkS3QOJBv6/3OPumbBfw== +emoji-regex@^10.3.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.4.0.tgz#03553afea80b3975749cfcb36f776ca268e413d4" + integrity sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" @@ -1804,6 +2052,11 @@ envinfo@^7.7.3: resolved "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== +environment@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/environment/-/environment-1.1.0.tgz#8e86c66b180f363c7ab311787e0259665f45a9f1" + integrity sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q== + es-module-lexer@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz#ba303831f63e6a394983fde2f97ad77b22324527" @@ -1819,7 +2072,7 @@ escalade@^3.1.1: resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== -escape-string-regexp@4.0.0: +escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== @@ -1841,6 +2094,15 @@ escodegen@^1.9.1: optionalDependencies: source-map "~0.6.1" +eslint-plugin-mocha@^10.5.0: + version "10.5.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-mocha/-/eslint-plugin-mocha-10.5.0.tgz#0aca8d709e7cddef566e0dc252f6b02e307a2b7e" + integrity sha512-F2ALmQVPT1GoP27O1JTZGrV9Pqg8k79OeIuvw63UxMtQKREZtmkK1NFgkZQ2TW7L2JSSFKHFPTtHu5z8R9QNRw== + dependencies: + eslint-utils "^3.0.0" + globals "^13.24.0" + rambda "^7.4.0" + eslint-scope@5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" @@ -1849,6 +2111,86 @@ eslint-scope@5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" +eslint-scope@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.1.0.tgz#70214a174d4cbffbc3e8a26911d8bf51b9ae9d30" + integrity sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz#1f785cc5e81eb7534523d85922248232077d2f8c" + integrity sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg== + +eslint@^9.12.0: + version "9.12.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.12.0.tgz#54fcba2876c90528396da0fa44b6446329031e86" + integrity sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.11.0" + "@eslint/config-array" "^0.18.0" + "@eslint/core" "^0.6.0" + "@eslint/eslintrc" "^3.1.0" + "@eslint/js" "9.12.0" + "@eslint/plugin-kit" "^0.2.0" + "@humanfs/node" "^0.16.5" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.3.1" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.1.0" + eslint-visitor-keys "^4.1.0" + espree "^10.2.0" + esquery "^1.5.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + text-table "^0.2.0" + +espree@^10.0.1, espree@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.2.0.tgz#f4bcead9e05b0615c968e85f83816bc386a45df6" + integrity sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g== + dependencies: + acorn "^8.12.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.1.0" + esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" @@ -1861,6 +2203,13 @@ espurify@^1.6.0: dependencies: core-js "^2.0.0" +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" @@ -1873,7 +2222,7 @@ estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.2.0: +estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== @@ -1883,7 +2232,7 @@ esutils@^2.0.2: resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -eventemitter3@^5.0.0: +eventemitter3@^5.0.0, eventemitter3@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== @@ -1893,6 +2242,21 @@ events@^3.2.0: resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +execa@~8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" + integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^8.0.1" + human-signals "^5.0.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^4.1.0" + strip-final-newline "^3.0.0" + expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz" @@ -1922,7 +2286,7 @@ extsprintf@^1.2.0: resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz" integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== -fast-deep-equal@^3.1.1: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== @@ -1943,6 +2307,17 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-patch@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz#85064ea1b1ebf97a3f7ad01e23f9337e72c66947" @@ -1953,6 +2328,11 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + fast-levenshtein@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz#37b899ae47e1090e40e3fd2318e4d5f0142ca912" @@ -1960,11 +2340,6 @@ fast-levenshtein@^3.0.0: dependencies: fastest-levenshtein "^1.0.7" -fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - fastest-levenshtein@^1.0.12, fastest-levenshtein@^1.0.7: version "1.0.16" resolved "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" @@ -2007,6 +2382,13 @@ fetch-ponyfill@^7.1.0: dependencies: node-fetch "~2.6.1" +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + fill-range@^7.0.1: version "7.0.1" resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -2014,6 +2396,13 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + find-cache-dir@^3.2.0: version "3.3.2" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" @@ -2023,7 +2412,7 @@ find-cache-dir@^3.2.0: make-dir "^3.0.2" pkg-dir "^4.1.0" -find-up@5.0.0: +find-up@5.0.0, find-up@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== @@ -2065,6 +2454,14 @@ flagged-respawn@^2.0.0: resolved "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-2.0.0.tgz#abf39719dcfe1ac06c86c9466081c541c682987b" integrity sha512-Gq/a6YCi8zexmGHMuJwahTGzXlAZAOsbCVKduWXC6TlLCjjFRlExMJc4GC2NYPYZ0r/brw9P7CpRgQmlPVeOoA== +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + flat@^5.0.2: version "5.0.2" resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" @@ -2075,6 +2472,11 @@ flatpickr@*: resolved "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.13.tgz#8a029548187fd6e0d670908471e43abe9ad18d94" integrity sha512-97PMG/aywoYpB4IvbvUJi0RQi8vearvU0oov1WW3k0WZPBMrTQVqekSX5CjSG/M4Q3i6A/0FKXC7RyAoAUUSPw== +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + for-in@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz" @@ -2156,6 +2558,11 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-east-asian-width@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz#21b4071ee58ed04ee0db653371b55b4299875389" + integrity sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ== + get-func-name@^2.0.1, get-func-name@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" @@ -2175,6 +2582,11 @@ get-package-type@^0.1.0: resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-stream@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" + integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== + getpass@^0.1.1: version "0.1.7" resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz" @@ -2279,6 +2691,23 @@ globals@^11.1.0: resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +globals@^13.24.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globals@^15.11.0: + version "15.11.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.11.0.tgz#b96ed4c6998540c6fb824b24b5499216d2438d6e" + integrity sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw== + globby@^11.0.4: version "11.1.0" resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -2303,6 +2732,11 @@ graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.2.10, graceful-fs@^4.2.1 resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + gulp-cli@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/gulp-cli/-/gulp-cli-3.0.0.tgz#577008f5323fad6106b44db24803c27c3a649841" @@ -2468,6 +2902,16 @@ https-proxy-agent@^5.0.1: agent-base "6" debug "4" +human-signals@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" + integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== + +husky@>=6: + version "9.1.6" + resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.6.tgz#e23aa996b6203ab33534bdc82306b0cf2cb07d6c" + integrity sha512-sqbjZKK7kf44hfdE94EoX8MZNk0n7HeW37O4YrVGCF4wzgQjp+akPAkfUK5LZ6KuR/6sqeAVuXHji+RzQgOn5A== + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" @@ -2492,6 +2936,19 @@ ignore@^5.2.0: resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== +ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-local@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" @@ -2575,7 +3032,19 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: +is-fullwidth-code-point@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" + integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + +is-fullwidth-code-point@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz#9609efced7c2f97da7b60145ef481c787c7ba704" + integrity sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA== + dependencies: + get-east-asian-width "^1.0.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -2626,6 +3095,11 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + is-subset@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz" @@ -2757,7 +3231,7 @@ js-tokens@^4.0.0: resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@4.1.0: +js-yaml@4.1.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -2848,6 +3322,11 @@ jsesc@^2.5.1: resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-logic-js@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/json-logic-js/-/json-logic-js-2.0.5.tgz#55f0c687dd6f56b02ccdcfdd64171ed998ab5499" @@ -2868,6 +3347,11 @@ json-schema@0.4.0: resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz" integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" @@ -2898,6 +3382,13 @@ just-extend@^6.2.0: resolved "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz#b816abfb3d67ee860482e7401564672558163947" integrity sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw== +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + kind-of@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" @@ -2923,6 +3414,14 @@ left-pad@^1.3.0: resolved "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz" integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + levn@~0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" @@ -2944,6 +3443,39 @@ liftoff@^5.0.0: rechoir "^0.8.0" resolve "^1.20.0" +lilconfig@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.2.tgz#e4a7c3cb549e3a606c8dcc32e5ae1005e62c05cb" + integrity sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow== + +lint-staged@>=10: + version "15.2.10" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.10.tgz#92ac222f802ba911897dcf23671da5bb80643cd2" + integrity sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg== + dependencies: + chalk "~5.3.0" + commander "~12.1.0" + debug "~4.3.6" + execa "~8.0.1" + lilconfig "~3.1.2" + listr2 "~8.2.4" + micromatch "~4.0.8" + pidtree "~0.6.0" + string-argv "~0.3.2" + yaml "~2.5.0" + +listr2@~8.2.4: + version "8.2.5" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.2.5.tgz#5c9db996e1afeb05db0448196d3d5f64fec2593d" + integrity sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ== + dependencies: + cli-truncate "^4.0.0" + colorette "^2.0.20" + eventemitter3 "^5.0.1" + log-update "^6.1.0" + rfdc "^1.4.1" + wrap-ansi "^9.0.0" + loader-runner@^4.2.0: version "4.3.0" resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" @@ -2978,6 +3510,11 @@ lodash.isequal@^4.5.0: resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz" integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz" @@ -2996,6 +3533,17 @@ log-symbols@4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" +log-update@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-6.1.0.tgz#1a04ff38166f94647ae1af562f4bd6a15b1b7cd4" + integrity sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w== + dependencies: + ansi-escapes "^7.0.0" + cli-cursor "^5.0.0" + slice-ansi "^7.1.0" + strip-ansi "^7.1.0" + wrap-ansi "^9.0.0" + loupe@^2.3.6: version "2.3.7" resolved "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" @@ -3069,6 +3617,14 @@ micromatch@^4.0.0, micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" +micromatch@~4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + mime-db@1.52.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -3081,6 +3637,16 @@ mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.19: dependencies: mime-db "1.52.0" +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + +mimic-function@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076" + integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== + min-document@^2.19.0: version "2.19.0" resolved "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" @@ -3095,7 +3661,7 @@ minimatch@5.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^3.0.4, minimatch@^3.1.1: +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -3116,6 +3682,13 @@ minimatch@^9.0.3: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.6: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" @@ -3172,7 +3745,7 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3: +ms@2.1.3, ms@^2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -3187,6 +3760,11 @@ mylas@^2.1.9: resolved "https://registry.npmjs.org/mylas/-/mylas-2.1.13.tgz#1e23b37d58fdcc76e15d8a5ed23f9ae9fc0cbdf4" integrity sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg== +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + neo-async@^2.6.2: version "2.6.2" resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" @@ -3239,6 +3817,13 @@ now-and-later@^3.0.0: dependencies: once "^1.4.0" +npm-run-path@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" + integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== + dependencies: + path-key "^4.0.0" + nwsapi@^2.0.7: version "2.2.2" resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz" @@ -3316,6 +3901,20 @@ once@^1.3.0, once@^1.4.0: dependencies: wrappy "1" +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + +onetime@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-7.0.0.tgz#9f16c92d8c9ef5120e3acd9dd9957cceecc1ab60" + integrity sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ== + dependencies: + mimic-function "^5.0.0" + optionator@^0.8.1: version "0.8.3" resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" @@ -3328,6 +3927,18 @@ optionator@^0.8.1: type-check "~0.3.2" word-wrap "~1.2.3" +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + p-limit@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -3378,6 +3989,13 @@ package-hash@^4.0.0: lodash.flattendeep "^4.4.0" release-zalgo "^1.0.0" +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + parse-filepath@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891" @@ -3419,6 +4037,11 @@ path-key@^3.1.0: resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + path-parse@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -3471,6 +4094,11 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pidtree@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" + integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== + pkg-dir@^4.1.0, pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" @@ -3600,11 +4228,21 @@ power-assert@^1.6.1: universal-deep-strict-equal "^1.2.1" xtend "^4.0.0" +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== +prettier@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" @@ -3667,6 +4305,11 @@ queue-tick@^1.0.1: resolved "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag== +rambda@^7.4.0: + version "7.5.0" + resolved "https://registry.yarnpkg.com/rambda/-/rambda-7.5.0.tgz#1865044c59bc0b16f63026c6e5a97e4b1bbe98fe" + integrity sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA== + randombytes@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -3819,6 +4462,11 @@ resolve-dir@^1.0.0, resolve-dir@^1.0.1: expand-tilde "^2.0.0" global-modules "^1.0.0" +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve-from@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" @@ -3840,11 +4488,24 @@ resolve@^1.20.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +restore-cursor@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-5.1.0.tgz#0766d95699efacb14150993f55baf0953ea1ebe7" + integrity sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA== + dependencies: + onetime "^7.0.0" + signal-exit "^4.1.0" + reusify@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rfdc@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== + rimraf@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -3938,6 +4599,11 @@ semver@^7.5.3: resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== +semver@^7.6.0: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + serialize-javascript@6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz" @@ -3991,6 +4657,11 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + sinon@^17.0.2: version "17.0.2" resolved "https://registry.npmjs.org/sinon/-/sinon-17.0.2.tgz#470894bcc2d24b01bad539722ea46da949892405" @@ -4008,6 +4679,22 @@ slash@^3.0.0: resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +slice-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" + integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== + dependencies: + ansi-styles "^6.0.0" + is-fullwidth-code-point "^4.0.0" + +slice-ansi@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-7.1.0.tgz#cd6b4655e298a8d1bdeb04250a433094b347b9a9" + integrity sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg== + dependencies: + ansi-styles "^6.2.1" + is-fullwidth-code-point "^5.0.0" + source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -4097,6 +4784,11 @@ streamx@^2.12.0, streamx@^2.12.5, streamx@^2.13.2, streamx@^2.14.0: optionalDependencies: bare-events "^2.2.0" +string-argv@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== + string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" @@ -4106,6 +4798,15 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string-width@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc" + integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ== + dependencies: + emoji-regex "^10.3.0" + get-east-asian-width "^1.0.0" + strip-ansi "^7.1.0" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -4141,6 +4842,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -4151,7 +4859,12 @@ strip-bom@^4.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== -strip-json-comments@3.1.1: +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + +strip-json-comments@3.1.1, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -4236,6 +4949,11 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + through2@^2.0.0: version "2.0.5" resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz" @@ -4305,6 +5023,11 @@ traverse@^0.6.6: resolved "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz" integrity sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg== +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + ts-loader@^9.5.0: version "9.5.1" resolved "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz#63d5912a86312f1fbe32cef0859fb8b2193d9b89" @@ -4377,6 +5100,13 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + type-check@~0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" @@ -4389,6 +5119,11 @@ type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.8: resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-fest@^0.8.0: version "0.8.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" @@ -4416,6 +5151,15 @@ typedoc@^0.25.13: minimatch "^9.0.3" shiki "^0.14.7" +typescript-eslint@^8.8.1: + version "8.8.1" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.8.1.tgz#b375c877b2184d883b6228170bc66f0fca847c9a" + integrity sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ== + dependencies: + "@typescript-eslint/eslint-plugin" "8.8.1" + "@typescript-eslint/parser" "8.8.1" + "@typescript-eslint/utils" "8.8.1" + typescript@^5.4.5: version "5.4.5" resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" @@ -4767,6 +5511,11 @@ wildcard@^2.0.0: resolved "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" @@ -4795,6 +5544,15 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-9.0.0.tgz#1a3dc8b70d85eeb8398ddfb1e4a02cd186e58b3e" + integrity sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q== + dependencies: + ansi-styles "^6.2.1" + string-width "^7.0.0" + strip-ansi "^7.1.0" + wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" @@ -4810,11 +5568,6 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -written-number@^0.11.1: - version "0.11.1" - resolved "https://registry.npmjs.org/written-number/-/written-number-0.11.1.tgz#ef060a7b5ad5ff8fbf4ff88daa8fb2260726ecc9" - integrity sha512-LhQ68uUnzHH0bwm/QiGA9JwqgadSDOwqB2AIs/LBsrOY6ScqVXKRN2slTCeKAhstDBJ/Of/Yxcjn0pnQmVlmtg== - ws@^5.2.0: version "5.2.3" resolved "https://registry.npmjs.org/ws/-/ws-5.2.3.tgz" @@ -4867,6 +5620,11 @@ yallist@^4.0.0: resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml@~2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.1.tgz#c9772aacf62cb7494a95b0c4f1fb065b563db130" + integrity sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q== + yargs-parser@20.2.4: version "20.2.4" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz"