fix: Fix mismatch between errors in debugger and evaluated value popup (#7752)

This commit is contained in:
akash-codemonk 2021-09-29 17:33:11 +05:30 committed by GitHub
parent c3724d5df2
commit 48f2c584ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 240 additions and 178 deletions

View File

@ -116,8 +116,8 @@
"currentRowWithIdOutside": "#{{currentRow.email}}", "currentRowWithIdOutside": "#{{currentRow.email}}",
"currentRowWithIdInside": "{{\"#\" + currentRow.email}}", "currentRowWithIdInside": "{{\"#\" + currentRow.email}}",
"defaultdataBinding": "{'Test','This'}", "defaultdataBinding": "{'Test','This'}",
"dropdownErrorMsg": "This value does not evaluate to type \"Array<{ \"label\": \"string\", \"value\": \"string\" }>\".", "dropdownErrorMsg": "This value does not evaluate to type Array<{ \"label\": \"string\", \"value\": \"string\" }>",
"tableWidgetErrorMsg": "This value does not evaluate to type \"Array<Object>\".", "tableWidgetErrorMsg": "This value does not evaluate to type Array<Object>",
"bindingDataPoint": "{{JSON.stringify(Chart1.selectedDataPoint)}}", "bindingDataPoint": "{{JSON.stringify(Chart1.selectedDataPoint)}}",
"bindingSeriesTitle": "{{Chart1.selectedDataPoint.seriesTitle", "bindingSeriesTitle": "{{Chart1.selectedDataPoint.seriesTitle",
"bindChartData": "{{Chart1.selectedDataPoint", "bindChartData": "{{Chart1.selectedDataPoint",

View File

@ -61,9 +61,7 @@ describe("DatePicker Widget Property pane tests with js bindings", function() {
it("Datepicker default date validation message", function() { it("Datepicker default date validation message", function() {
cy.openPropertyPane("datepickerwidget2"); cy.openPropertyPane("datepickerwidget2");
cy.testJsontext("defaultdate", "24-12-2021"); cy.testJsontext("defaultdate", "24-12-2021");
cy.evaluateErrorMessage( cy.evaluateErrorMessage("Value does not match: ISO 8601 date string");
`This value does not evaluate to type "ISO 8601 date string".`,
);
cy.closePropertyPane(); cy.closePropertyPane();
}); });

View File

@ -21,10 +21,7 @@ import { IPopoverSharedProps } from "@blueprintjs/core";
import { ReactComponent as CopyIcon } from "assets/icons/menu/copy-snippet.svg"; import { ReactComponent as CopyIcon } from "assets/icons/menu/copy-snippet.svg";
import copy from "copy-to-clipboard"; import copy from "copy-to-clipboard";
import { import { EvaluationError } from "utils/DynamicBindingUtils";
EvaluationError,
PropertyEvaluationErrorType,
} from "utils/DynamicBindingUtils";
import * as Sentry from "@sentry/react"; import * as Sentry from "@sentry/react";
import { Severity } from "@sentry/react"; import { Severity } from "@sentry/react";
import { CodeEditorExpected } from "components/editorComponents/CodeEditor/index"; import { CodeEditorExpected } from "components/editorComponents/CodeEditor/index";
@ -387,9 +384,9 @@ function PopoverContent(props: PopoverContentProps) {
{hasError && error && ( {hasError && error && (
<ErrorText> <ErrorText>
<span className="t--evaluatedPopup-error"> <span className="t--evaluatedPopup-error">
{error.errorType === PropertyEvaluationErrorType.VALIDATION {/* errorMessage could be an empty string */}
? `This value does not evaluate to type "${expected?.type}".` {error.errorMessage ||
: error.errorMessage} `This value does not evaluate to type "${expected?.type}".`}
</span> </span>
<EvaluatedValueDebugButton <EvaluatedValueDebugButton
entity={props.entity} entity={props.entity}

View File

@ -20,7 +20,7 @@ export enum ValidationTypes {
export type ValidationResponse = { export type ValidationResponse = {
isValid: boolean; isValid: boolean;
parsed: any; parsed: any;
message?: string; messages?: string[];
transformed?: any; transformed?: any;
}; };

View File

@ -463,12 +463,14 @@ export function* evaluateArgumentSaga(action: any) {
if (workerResponse.result) { if (workerResponse.result) {
const validation = validate({ type }, workerResponse.result, {}); const validation = validate({ type }, workerResponse.result, {});
if (!validation.isValid) if (!validation.isValid)
lintErrors.unshift({ validation.messages?.map((message) => {
...validation, lintErrors.unshift({
...{ ...validation,
errorType: PropertyEvaluationErrorType.VALIDATION, ...{
errorMessage: validation.message, errorType: PropertyEvaluationErrorType.VALIDATION,
}, errorMessage: message,
},
});
}); });
} }
yield put( yield put(

View File

@ -57,7 +57,7 @@ function defaultSelectedValuesValidation(
return { return {
isValid: false, isValid: false,
parsed: values, parsed: values,
message: messages.join(" "), messages,
}; };
} }

View File

@ -24,14 +24,14 @@ function defaultDateValidation(
return { return {
isValid: true, isValid: true,
parsed: "", parsed: "",
message: "", messages: [""],
}; };
} }
if (value === undefined) { if (value === undefined) {
return { return {
isValid: false, isValid: false,
parsed: "", parsed: "",
message: `This value does not evaluate to type: Date ${dateFormat}`, messages: [`This value does not evaluate to type: Date ${dateFormat}`],
}; };
} }
@ -40,10 +40,10 @@ function defaultDateValidation(
return { return {
isValid, isValid,
parsed: isValid ? value : "", parsed: isValid ? value : "",
message: messages:
isValid === false isValid === false
? `Value does not match ISO 8601 standard date string` ? [`Value does not match ISO 8601 standard date string`]
: "", : [""],
}; };
} }
@ -58,8 +58,9 @@ function minDateValidation(
return { return {
isValid: false, isValid: false,
parsed: "", parsed: "",
message: messages: [
`Value does not match: Date String ` + (dateFormat ? dateFormat : ""), `Value does not match: Date String ` + (dateFormat ? dateFormat : ""),
],
}; };
} }
const parsedMinDate = moment(value as string, dateFormat); const parsedMinDate = moment(value as string, dateFormat);
@ -69,7 +70,7 @@ function minDateValidation(
return { return {
isValid: isValid, isValid: isValid,
parsed: value, parsed: value,
message: "", messages: [""],
}; };
} }
const parsedDefaultDate = moment(props.defaultDate, dateFormat); const parsedDefaultDate = moment(props.defaultDate, dateFormat);
@ -85,14 +86,15 @@ function minDateValidation(
return { return {
isValid: isValid, isValid: isValid,
parsed: "", parsed: "",
message: messages: [
`Value does not match: Date String ` + (dateFormat ? dateFormat : ""), `Value does not match: Date String ` + (dateFormat ? dateFormat : ""),
],
}; };
} }
return { return {
isValid: isValid, isValid: isValid,
parsed: value, parsed: value,
message: "", messages: [""],
}; };
} }
@ -107,9 +109,10 @@ function maxDateValidation(
return { return {
isValid: false, isValid: false,
parsed: "", parsed: "",
message: messages: [
`Value does not match type: Date String ` + `Value does not match type: Date String ` +
(dateFormat ? dateFormat : ""), (dateFormat ? dateFormat : ""),
],
}; };
} }
const parsedMaxDate = moment(value as string, dateFormat); const parsedMaxDate = moment(value as string, dateFormat);
@ -118,7 +121,7 @@ function maxDateValidation(
return { return {
isValid: isValid, isValid: isValid,
parsed: value, parsed: value,
message: "", messages: [""],
}; };
} }
const parsedDefaultDate = moment(props.defaultDate, dateFormat); const parsedDefaultDate = moment(props.defaultDate, dateFormat);
@ -134,15 +137,16 @@ function maxDateValidation(
return { return {
isValid: isValid, isValid: isValid,
parsed: "", parsed: "",
message: messages: [
`Value does not match type: Date String ` + `Value does not match type: Date String ` +
(dateFormat ? dateFormat : ""), (dateFormat ? dateFormat : ""),
],
}; };
} }
return { return {
isValid: isValid, isValid: isValid,
parsed: value, parsed: value,
message: "", messages: [""],
}; };
} }
class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> { class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {

View File

@ -18,7 +18,7 @@ function defaultOptionValueValidation(value: unknown): ValidationResponse {
return { return {
isValid: false, isValid: false,
parsed: "", parsed: "",
message: "This value does not evaluate to type: string", messages: ["This value does not evaluate to type: string"],
}; };
return { isValid: true, parsed: value }; return { isValid: true, parsed: value };
} }

View File

@ -37,24 +37,24 @@ describe("#defaultValueValidation", () => {
"abcd", "abcd",
]; ];
const expectedOutputs = [ const expectedOutputs = [
{ isValid: true, parsed: undefined, message: "" }, { isValid: true, parsed: undefined, messages: [""] },
{ isValid: true, parsed: undefined, message: "" }, { isValid: true, parsed: undefined, messages: [""] },
{ isValid: true, parsed: 0, message: "" }, { isValid: true, parsed: 0, messages: [""] },
{ isValid: true, parsed: 123, message: "" }, { isValid: true, parsed: 123, messages: [""] },
{ isValid: true, parsed: -23, message: "" }, { isValid: true, parsed: -23, messages: [""] },
{ isValid: true, parsed: 0.000001, message: "" }, { isValid: true, parsed: 0.000001, messages: [""] },
{ isValid: true, parsed: -23, message: "" }, { isValid: true, parsed: -23, messages: [""] },
{ isValid: true, parsed: 0, message: "" }, { isValid: true, parsed: 0, messages: [""] },
{ isValid: true, parsed: 100, message: "" }, { isValid: true, parsed: 100, messages: [""] },
{ {
isValid: false, isValid: false,
parsed: undefined, parsed: undefined,
message: "This value must be a number", messages: ["This value must be a number"],
}, },
{ {
isValid: false, isValid: false,
parsed: undefined, parsed: undefined,
message: "This value must be a number", messages: ["This value must be a number"],
}, },
]; ];

View File

@ -43,7 +43,7 @@ export function defaultValueValidation(
return { return {
isValid: true, isValid: true,
parsed: undefined, parsed: undefined,
message: "", messages: [""],
}; };
} }
@ -51,7 +51,7 @@ export function defaultValueValidation(
return { return {
isValid: false, isValid: false,
parsed: undefined, parsed: undefined,
message: "This value must be a number", messages: ["This value must be a number"],
}; };
} }
} }
@ -59,14 +59,14 @@ export function defaultValueValidation(
return { return {
isValid: true, isValid: true,
parsed, parsed,
message: "", messages: [""],
}; };
} }
if (_.isObject(value)) { if (_.isObject(value)) {
return { return {
isValid: false, isValid: false,
parsed: JSON.stringify(value, null, 2), parsed: JSON.stringify(value, null, 2),
message: "This value must be string", messages: ["This value must be string"],
}; };
} }
let parsed = value; let parsed = value;
@ -78,14 +78,14 @@ export function defaultValueValidation(
return { return {
isValid: false, isValid: false,
parsed: "", parsed: "",
message: "This value must be string", messages: ["This value must be string"],
}; };
} }
} }
return { return {
isValid, isValid,
parsed: parsed, parsed: parsed,
message: "", messages: [""],
}; };
} }

View File

@ -29,7 +29,7 @@ function validateDefaultRate(value: unknown, props: any, _: any) {
return { return {
isValid: false, isValid: false,
parsed: 0, parsed: 0,
message: `Value must be a number`, messages: [`Value must be a number`],
}; };
} }
} }
@ -43,7 +43,7 @@ function validateDefaultRate(value: unknown, props: any, _: any) {
return { return {
isValid: false, isValid: false,
parsed, parsed,
message: `This value must be less than or equal to max count`, messages: [`This value must be less than or equal to max count`],
}; };
} }
@ -52,7 +52,7 @@ function validateDefaultRate(value: unknown, props: any, _: any) {
return { return {
isValid: false, isValid: false,
parsed, parsed,
message: `This value can be a decimal only if 'Allow half' is true`, messages: [`This value can be a decimal only if 'Allow half' is true`],
}; };
} }
@ -61,7 +61,7 @@ function validateDefaultRate(value: unknown, props: any, _: any) {
return { return {
isValid: false, isValid: false,
parsed: value, parsed: value,
message: `Could not validate `, messages: [`Could not validate `],
}; };
} }
} }

View File

@ -21,7 +21,7 @@ function defaultOptionValueValidation(value: unknown): ValidationResponse {
return { return {
isValid: false, isValid: false,
parsed: "", parsed: "",
message: "This value does not evaluate to type: string", messages: ["This value does not evaluate to type: string"],
}; };
return { isValid: true, parsed: value }; return { isValid: true, parsed: value };
} }

View File

@ -25,7 +25,7 @@ export function selectedTabValidation(
return { return {
isValid: value === "" ? true : tabNames.includes(value as string), isValid: value === "" ? true : tabNames.includes(value as string),
parsed: value, parsed: value,
message: `Tab name ${value} does not exist`, messages: [`Tab name ${value} does not exist`],
}; };
} }
class TabsWidget extends BaseWidget< class TabsWidget extends BaseWidget<

View File

@ -2,6 +2,7 @@ import {
DependencyMap, DependencyMap,
EvalError, EvalError,
EvalErrorTypes, EvalErrorTypes,
EvaluationError,
getDynamicBindings, getDynamicBindings,
getEntityDynamicBindingPathList, getEntityDynamicBindingPathList,
getEvalErrorPath, getEvalErrorPath,
@ -731,7 +732,7 @@ export default class DataTreeEvaluator {
} }
const validation = widget.validationPaths[propertyPath]; const validation = widget.validationPaths[propertyPath];
const { isValid, message, parsed, transformed } = validateWidgetProperty( const { isValid, messages, parsed, transformed } = validateWidgetProperty(
validation, validation,
valueToValidate, valueToValidate,
widget, widget,
@ -749,18 +750,16 @@ export default class DataTreeEvaluator {
safeEvaluatedValue, safeEvaluatedValue,
); );
if (!isValid) { if (!isValid) {
addErrorToEntityProperty( const evalErrors: EvaluationError[] =
[ messages?.map((message) => {
{ return {
raw: unEvalPropertyValue, raw: unEvalPropertyValue,
errorMessage: message || "", errorMessage: message || "",
errorType: PropertyEvaluationErrorType.VALIDATION, errorType: PropertyEvaluationErrorType.VALIDATION,
severity: Severity.ERROR, severity: Severity.ERROR,
}, };
], }) ?? [];
currentTree, addErrorToEntityProperty(evalErrors, currentTree, fullPropertyPath);
fullPropertyPath,
);
} }
if (isPathADynamicTrigger(widget, propertyPath)) { if (isPathADynamicTrigger(widget, propertyPath)) {

View File

@ -357,7 +357,7 @@ export function getValidatedTree(tree: DataTree) {
Object.entries(entity.validationPaths).forEach(([property, validation]) => { Object.entries(entity.validationPaths).forEach(([property, validation]) => {
const value = _.get(entity, property); const value = _.get(entity, property);
// Pass it through parse // Pass it through parse
const { isValid, message, parsed, transformed } = validateWidgetProperty( const { isValid, messages, parsed, transformed } = validateWidgetProperty(
validation, validation,
value, value,
entity, entity,
@ -375,15 +375,15 @@ export function getValidatedTree(tree: DataTree) {
safeEvaluatedValue, safeEvaluatedValue,
); );
if (!isValid) { if (!isValid) {
const evalErrors: EvaluationError[] =
messages?.map((message) => ({
errorType: PropertyEvaluationErrorType.VALIDATION,
errorMessage: message,
severity: Severity.ERROR,
raw: value,
})) ?? [];
addErrorToEntityProperty( addErrorToEntityProperty(
[ evalErrors,
{
errorType: PropertyEvaluationErrorType.VALIDATION,
errorMessage: message || "",
severity: Severity.ERROR,
raw: value,
},
],
tree, tree,
getEvalErrorPath(`${entityKey}.${property}`, false), getEvalErrorPath(`${entityKey}.${property}`, false),
); );

View File

@ -38,27 +38,35 @@ describe("Validate Validators", () => {
{ {
isValid: false, isValid: false,
parsed: "abc", parsed: "abc",
message: "Value is not allowed", messages: ["Value is not allowed"],
}, },
{ {
isValid: false, isValid: false,
parsed: "abc", parsed: "abc",
message: `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`,
],
}, },
{ {
isValid: false, isValid: false,
parsed: "abc", parsed: "abc",
message: `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`,
],
}, },
{ {
isValid: false, isValid: false,
parsed: "{}", parsed: "{}",
message: `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`,
],
}, },
{ {
isValid: false, isValid: false,
parsed: "[]", parsed: "[]",
message: `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`,
],
}, },
{ {
isValid: true, isValid: true,
@ -115,12 +123,14 @@ describe("Validate Validators", () => {
{ {
isValid: false, isValid: false,
parsed: "abc", parsed: "abc",
message: "Value is not allowed", messages: ["Value is not allowed"],
}, },
{ {
isValid: false, isValid: false,
parsed: "abc", parsed: "abc",
message: `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`,
],
}, },
]; ];
inputs.forEach((input, index) => { inputs.forEach((input, index) => {
@ -166,7 +176,9 @@ describe("Validate Validators", () => {
isValid: false, isValid: false,
parsed: parsed:
"https://cdn.dribbble.com/users/1787323/screenshots/4563995/dribbbe_hammer-01.png", "https://cdn.dribbble.com/users/1787323/screenshots/4563995/dribbbe_hammer-01.png",
message: `${WIDGET_TYPE_VALIDATION_ERROR}: base64 encoded image | data uri | image url`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR}: base64 encoded image | data uri | image url`,
],
}, },
]; ];
@ -195,27 +207,31 @@ describe("Validate Validators", () => {
{ {
isValid: false, isValid: false,
parsed: 90, parsed: 90,
message: "Minimum allowed value: 100", messages: ["Minimum allowed value: 100"],
}, },
{ {
isValid: false, isValid: false,
parsed: 220, parsed: 220,
message: "Maximum allowed value: 200", messages: ["Maximum allowed value: 200"],
}, },
{ {
isValid: false, isValid: false,
parsed: 150, parsed: 150,
message: "This value is required", messages: ["This value is required"],
}, },
{ {
isValid: false, isValid: false,
parsed: 150, parsed: 150,
message: `${WIDGET_TYPE_VALIDATION_ERROR} number Min: 100 Max: 200 Required`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR} number Min: 100 Max: 200 Required`,
],
}, },
{ {
isValid: false, isValid: false,
parsed: 150, parsed: 150,
message: `${WIDGET_TYPE_VALIDATION_ERROR} number Min: 100 Max: 200 Required`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR} number Min: 100 Max: 200 Required`,
],
}, },
{ {
isValid: true, isValid: true,
@ -224,7 +240,7 @@ describe("Validate Validators", () => {
{ {
isValid: false, isValid: false,
parsed: 150, parsed: 150,
message: "This value is required", messages: ["This value is required"],
}, },
]; ];
inputs.forEach((input, index) => { inputs.forEach((input, index) => {
@ -267,12 +283,12 @@ describe("Validate Validators", () => {
const expected = [ const expected = [
{ {
isValid: false, isValid: false,
message: `${WIDGET_TYPE_VALIDATION_ERROR} boolean`, messages: [`${WIDGET_TYPE_VALIDATION_ERROR} boolean`],
parsed: false, parsed: false,
}, },
{ {
isValid: false, isValid: false,
message: `${WIDGET_TYPE_VALIDATION_ERROR} boolean`, messages: [`${WIDGET_TYPE_VALIDATION_ERROR} boolean`],
parsed: false, parsed: false,
}, },
{ {
@ -285,12 +301,12 @@ describe("Validate Validators", () => {
}, },
{ {
isValid: false, isValid: false,
message: `${WIDGET_TYPE_VALIDATION_ERROR} boolean`, messages: [`${WIDGET_TYPE_VALIDATION_ERROR} boolean`],
parsed: false, parsed: false,
}, },
{ {
isValid: false, isValid: false,
message: `${WIDGET_TYPE_VALIDATION_ERROR} boolean`, messages: [`${WIDGET_TYPE_VALIDATION_ERROR} boolean`],
parsed: false, parsed: false,
}, },
{ {
@ -304,7 +320,7 @@ describe("Validate Validators", () => {
{ {
isValid: false, isValid: false,
parsed: false, parsed: false,
message: "This value does not evaluate to type boolean", messages: ["This value does not evaluate to type boolean"],
}, },
]; ];
@ -388,27 +404,35 @@ describe("Validate Validators", () => {
{ {
isValid: false, isValid: false,
parsed: { key1: 120, key2: "abc" }, parsed: { key1: 120, key2: "abc" },
message: `${WIDGET_TYPE_VALIDATION_ERROR}: { \"key1\": \"number Required\", \"key2\": \"string ( abc | mnop )\" }`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR}: { \"key1\": \"number Required\", \"key2\": \"string ( abc | mnop )\" }`,
],
}, },
{ {
isValid: false, isValid: false,
parsed: { key1: 120, key2: "abc" }, parsed: { key1: 120, key2: "abc" },
message: `${WIDGET_TYPE_VALIDATION_ERROR}: { \"key1\": \"number Required\", \"key2\": \"string ( abc | mnop )\" }`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR}: { \"key1\": \"number Required\", \"key2\": \"string ( abc | mnop )\" }`,
],
}, },
{ {
isValid: false, isValid: false,
parsed: { key1: 120, key2: "abc" }, parsed: { key1: 120, key2: "abc" },
message: `Value of key: key1 is invalid: This value does not evaluate to type number Required`, messages: [
`Value of key: key1 is invalid: This value does not evaluate to type number Required`,
],
}, },
{ {
isValid: false, isValid: false,
parsed: { key1: 120, key2: "abc" }, parsed: { key1: 120, key2: "abc" },
message: `Value of key: key2 is invalid: This value does not evaluate to type string ( abc | mnop )`, messages: [
`Value of key: key2 is invalid: This value does not evaluate to type string ( abc | mnop )`,
],
}, },
{ {
isValid: false, isValid: false,
parsed: { key1: 120, key2: "abc" }, parsed: { key1: 120, key2: "abc" },
message: `Missing required key: key1`, messages: [`Missing required key: key1`],
}, },
]; ];
inputs.forEach((input, index) => { inputs.forEach((input, index) => {
@ -451,73 +475,79 @@ describe("Validate Validators", () => {
{ {
isValid: true, isValid: true,
parsed: ["a", "b", "c"], parsed: ["a", "b", "c"],
message: "", messages: [],
}, },
{ {
isValid: true, isValid: true,
parsed: ["m", "n", "b"], parsed: ["m", "n", "b"],
message: "", messages: [],
}, },
{ {
isValid: false, isValid: false,
parsed: [], parsed: [],
message: "Invalid entry at index: 2. Value is not allowed", messages: ["Invalid entry at index: 2. Value is not allowed"],
}, },
{ {
isValid: true, isValid: true,
parsed: [], parsed: [],
message: "", messages: [],
}, },
{ {
isValid: false, isValid: false,
parsed: [], parsed: [],
message: messages: [
"This value does not evaluate to type Array<string ( a | b | c | n | m | p | r )>", "This value does not evaluate to type Array<string ( a | b | c | n | m | p | r )>",
],
}, },
{ {
isValid: false, isValid: false,
parsed: [], parsed: [],
message: messages: [
"This property is required for the widget to function correctly", "This property is required for the widget to function correctly",
],
}, },
{ {
isValid: false, isValid: false,
parsed: [], parsed: [],
message: messages: [
"This property is required for the widget to function correctly", "This property is required for the widget to function correctly",
],
}, },
{ {
isValid: false, isValid: false,
parsed: [], parsed: [],
message: messages: [
"This value does not evaluate to type Array<string ( a | b | c | n | m | p | r )>", "This value does not evaluate to type Array<string ( a | b | c | n | m | p | r )>",
],
}, },
{ {
isValid: true, isValid: true,
parsed: ["a", "b", "c"], parsed: ["a", "b", "c"],
message: "", messages: [],
}, },
{ {
isValid: false, isValid: false,
parsed: [], parsed: [],
message: messages: [
"This value does not evaluate to type Array<string ( a | b | c | n | m | p | r )>", "This value does not evaluate to type Array<string ( a | b | c | n | m | p | r )>",
],
}, },
{ {
isValid: false, isValid: false,
parsed: [], parsed: [],
message: "Array must be unique. Duplicate values found", messages: ["Array must be unique. Duplicate values found"],
}, },
{ {
isValid: false, isValid: false,
parsed: [], parsed: [],
message: messages: [
"This property is required for the widget to function correctly", "This property is required for the widget to function correctly",
],
}, },
{ {
isValid: true, isValid: true,
parsed: [], parsed: [],
message: "", messages: [],
}, },
]; ];
inputs.forEach((input, index) => { inputs.forEach((input, index) => {
@ -594,39 +624,44 @@ describe("Validate Validators", () => {
{ {
isValid: true, isValid: true,
parsed: [{ label: 123, value: 234 }], parsed: [{ label: 123, value: 234 }],
message: "", messages: [],
}, },
{ {
isValid: true, isValid: true,
parsed: [{ label: 123, value: 234 }], parsed: [{ label: 123, value: 234 }],
message: "", messages: [],
}, },
{ {
isValid: false, isValid: false,
parsed: [], parsed: [],
message: "Invalid entry at index: 0. Missing required key: label", messages: ["Invalid entry at index: 0. Missing required key: label"],
}, },
{ {
isValid: false, isValid: false,
parsed: [], parsed: [],
message: `Invalid entry at index: 0. Value of key: label is invalid: This value does not evaluate to type number Required`, messages: [
`Invalid entry at index: 0. Value of key: label is invalid: This value does not evaluate to type number Required`,
],
}, },
{ {
isValid: false, isValid: false,
parsed: [], parsed: [],
message: messages: [
"Invalid entry at index: 0. Missing required key: label Missing required key: value", "Invalid entry at index: 0. Missing required key: label",
"Invalid entry at index: 0. Missing required key: value",
],
}, },
{ {
isValid: true, isValid: true,
parsed: [], parsed: [],
message: "", messages: [],
}, },
{ {
isValid: false, isValid: false,
parsed: [], parsed: [],
message: messages: [
"This property is required for the widget to function correctly", "This property is required for the widget to function correctly",
],
}, },
]; ];
inputs.forEach((input, index) => { inputs.forEach((input, index) => {
@ -711,16 +746,16 @@ describe("Validate Validators", () => {
{ {
isValid: false, isValid: false,
parsed: defaultDate, parsed: defaultDate,
message: "Value does not match: ISO 8601 date string", messages: ["Value does not match: ISO 8601 date string"],
}, },
{ {
isValid: false, isValid: false,
parsed: defaultDate, parsed: defaultDate,
message: "Value does not match: ISO 8601 date string", messages: ["Value does not match: ISO 8601 date string"],
}, },
{ {
isValid: false, isValid: false,
message: "Value does not match: ISO 8601 date string", messages: ["Value does not match: ISO 8601 date string"],
parsed: defaultDate, parsed: defaultDate,
}, },
]; ];
@ -800,52 +835,52 @@ describe("Validate Validators", () => {
{ {
isValid: false, isValid: false,
parsed: [{ id: 1, name: "alpha" }], parsed: [{ id: 1, name: "alpha" }],
message: "This value does not evaluate to type Array<Object>", messages: ["This value does not evaluate to type Array<Object>"],
}, },
{ {
isValid: false, isValid: false,
parsed: [{ id: 1, name: "alpha" }], parsed: [{ id: 1, name: "alpha" }],
message: "This value does not evaluate to type Array<Object>", messages: ["This value does not evaluate to type Array<Object>"],
}, },
{ {
isValid: false, isValid: false,
parsed: [{ id: 1, name: "alpha" }], parsed: [{ id: 1, name: "alpha" }],
message: "This value does not evaluate to type Array<Object>", messages: ["This value does not evaluate to type Array<Object>"],
}, },
{ {
isValid: false, isValid: false,
parsed: [{ id: 1, name: "alpha" }], parsed: [{ id: 1, name: "alpha" }],
message: "This value does not evaluate to type Array<Object>", messages: ["This value does not evaluate to type Array<Object>"],
}, },
{ {
isValid: false, isValid: false,
parsed: [{ id: 1, name: "alpha" }], parsed: [{ id: 1, name: "alpha" }],
message: "This value does not evaluate to type Array<Object>", messages: ["This value does not evaluate to type Array<Object>"],
}, },
{ {
isValid: false, isValid: false,
parsed: [{ id: 1, name: "alpha" }], parsed: [{ id: 1, name: "alpha" }],
message: "This value does not evaluate to type Array<Object>", messages: ["This value does not evaluate to type Array<Object>"],
}, },
{ {
isValid: false, isValid: false,
parsed: [{ id: 1, name: "alpha" }], parsed: [{ id: 1, name: "alpha" }],
message: "Invalid object at index 0", messages: ["Invalid object at index 0"],
}, },
{ {
isValid: false, isValid: false,
parsed: [{ id: 1, name: "alpha" }], parsed: [{ id: 1, name: "alpha" }],
message: "Invalid object at index 1", messages: ["Invalid object at index 1"],
}, },
{ {
isValid: false, isValid: false,
parsed: [{ id: 1, name: "alpha" }], parsed: [{ id: 1, name: "alpha" }],
message: "Invalid object at index 1", messages: ["Invalid object at index 1"],
}, },
{ {
isValid: false, isValid: false,
parsed: [{ id: 1, name: "alpha" }], parsed: [{ id: 1, name: "alpha" }],
message: "This value does not evaluate to type Array<Object>", messages: ["This value does not evaluate to type Array<Object>"],
}, },
]; ];
@ -928,12 +963,12 @@ describe("Validate Validators", () => {
}, },
{ {
isValid: false, isValid: false,
message: `${WIDGET_TYPE_VALIDATION_ERROR}: URL`, messages: [`${WIDGET_TYPE_VALIDATION_ERROR}: URL`],
parsed: "https://wikipedia.org", parsed: "https://wikipedia.org",
}, },
{ {
isValid: false, isValid: false,
message: `${WIDGET_TYPE_VALIDATION_ERROR}: URL`, messages: [`${WIDGET_TYPE_VALIDATION_ERROR}: URL`],
parsed: "https://wikipedia.org", parsed: "https://wikipedia.org",
}, },
]; ];

View File

@ -59,7 +59,7 @@ function validatePlainObject(
const entryName = getPropertyEntry(value, entry.name, ignoreCase); const entryName = getPropertyEntry(value, entry.name, ignoreCase);
if (value.hasOwnProperty(entryName)) { if (value.hasOwnProperty(entryName)) {
const { isValid, message, parsed } = validate( const { isValid, messages, parsed } = validate(
entry, entry,
value[entryName], value[entryName],
props, props,
@ -67,8 +67,12 @@ function validatePlainObject(
if (!isValid) { if (!isValid) {
value[entryName] = parsed; value[entryName] = parsed;
_valid = isValid; _valid = isValid;
message && messages &&
_messages.push(`Value of key: ${entryName} is invalid: ${message}`); messages.map((message) => {
_messages.push(
`Value of key: ${entryName} is invalid: ${message}`,
);
});
} }
} else if (entry.params?.required) { } else if (entry.params?.required) {
_valid = false; _valid = false;
@ -84,7 +88,7 @@ function validatePlainObject(
return { return {
isValid: false, isValid: false,
parsed: config.params?.default || value, parsed: config.params?.default || value,
message: _messages.join(" "), messages: _messages,
}; };
} }
return { return {
@ -107,7 +111,7 @@ function validateArray(
return { return {
isValid: false, isValid: false,
parsed: value, parsed: value,
message: `Disallowed value: ${entry}`, messages: [`Disallowed value: ${entry}`],
}; };
} }
}); });
@ -170,8 +174,8 @@ function validateArray(
const validation = validate(children, entry, props); const validation = validate(children, entry, props);
if (!validation.isValid) { if (!validation.isValid) {
_isValid = false; _isValid = false;
_messages.push( validation.messages?.map((message) =>
`Invalid entry at index: ${index}. ${validation.message}`, _messages.push(`Invalid entry at index: ${index}. ${message}`),
); );
} }
}); });
@ -185,7 +189,7 @@ function validateArray(
if (uniq(shouldBeUnique).length !== value.length) { if (uniq(shouldBeUnique).length !== value.length) {
_isValid = false; _isValid = false;
_messages.push( _messages.push(
`Array entry path:${param} must be unique. Duplicate values found`, `path:${param} must be unique. Duplicate values found`,
); );
break; break;
} }
@ -201,7 +205,7 @@ function validateArray(
return { return {
isValid: _isValid, isValid: _isValid,
parsed: _isValid ? value : config.params?.default || [], parsed: _isValid ? value : config.params?.default || [],
message: _messages.join(" "), messages: _messages,
}; };
} }
@ -296,7 +300,9 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
return { return {
isValid: false, isValid: false,
parsed: config.params?.default || "", parsed: config.params?.default || "",
message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`,
],
}; };
} }
@ -311,7 +317,9 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
return { return {
isValid: false, isValid: false,
parsed: JSON.stringify(value, null, 2), parsed: JSON.stringify(value, null, 2),
message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`,
],
}; };
} }
@ -319,7 +327,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
const stringValidationError = { const stringValidationError = {
isValid: false, isValid: false,
parsed: config.params?.default || "", parsed: config.params?.default || "",
message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, messages: [`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`],
}; };
if (!isValid) { if (!isValid) {
try { try {
@ -335,7 +343,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
if (!config.params?.allowedValues.includes((parsed as string).trim())) { if (!config.params?.allowedValues.includes((parsed as string).trim())) {
return { return {
parsed: config.params?.default || "", parsed: config.params?.default || "",
message: "Value is not allowed", messages: ["Value is not allowed"],
isValid: false, isValid: false,
}; };
} }
@ -348,7 +356,9 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
) { ) {
return { return {
parsed: config.params?.default || "", parsed: config.params?.default || "",
message: `Value does not match expected regex: ${config.params?.regex.source}`, messages: [
`Value does not match expected regex: ${config.params?.regex.source}`,
],
isValid: false, isValid: false,
}; };
} }
@ -364,7 +374,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
value: unknown, value: unknown,
props: Record<string, unknown>, props: Record<string, unknown>,
): ValidationResponse => { ): ValidationResponse => {
const { isValid, message, parsed } = VALIDATORS[ValidationTypes.TEXT]( const { isValid, messages, parsed } = VALIDATORS[ValidationTypes.TEXT](
config, config,
value, value,
props, props,
@ -374,11 +384,13 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
return { return {
isValid: false, isValid: false,
parsed: new RegExp(parsed), parsed: new RegExp(parsed),
message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`,
],
}; };
} }
return { isValid, parsed, message }; return { isValid, parsed, messages };
}, },
[ValidationTypes.NUMBER]: ( [ValidationTypes.NUMBER]: (
config: ValidationConfig, config: ValidationConfig,
@ -390,7 +402,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
return { return {
isValid: false, isValid: false,
parsed: config.params?.default || 0, parsed: config.params?.default || 0,
message: "This value is required", messages: ["This value is required"],
}; };
} }
@ -410,7 +422,9 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
return { return {
isValid: false, isValid: false,
parsed: config.params?.default || 0, parsed: config.params?.default || 0,
message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`,
],
}; };
} }
@ -423,7 +437,9 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
return { return {
isValid: false, isValid: false,
parsed: config.params?.default || 0, parsed: config.params?.default || 0,
message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`,
],
}; };
} }
} }
@ -436,7 +452,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
return { return {
isValid: false, isValid: false,
parsed, parsed,
message: `Minimum allowed value: ${config.params.min}`, messages: [`Minimum allowed value: ${config.params.min}`],
}; };
} }
} }
@ -449,7 +465,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
return { return {
isValid: false, isValid: false,
parsed, parsed,
message: `Maximum allowed value: ${config.params.max}`, messages: [`Maximum allowed value: ${config.params.max}`],
}; };
} }
} }
@ -457,7 +473,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
return { return {
isValid: false, isValid: false,
parsed, parsed,
message: `Value should be a positive integer`, messages: [`Value should be a positive integer`],
}; };
} }
@ -476,7 +492,9 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
return { return {
isValid: false, isValid: false,
parsed: !!config.params?.default, parsed: !!config.params?.default,
message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`,
],
}; };
} }
@ -500,7 +518,9 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
return { return {
isValid: false, isValid: false,
parsed: config.params?.default || false, parsed: config.params?.default || false,
message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`,
],
}; };
} }
@ -520,9 +540,9 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
return { return {
isValid: false, isValid: false,
parsed: config.params?.default || {}, parsed: config.params?.default || {},
message: `${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType( messages: [
config, `${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`,
)}`, ],
}; };
} }
return { return {
@ -547,13 +567,17 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
return { return {
isValid: false, isValid: false,
parsed: config.params?.default || {}, parsed: config.params?.default || {},
message: `${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`,
],
}; };
} catch (e) { } catch (e) {
return { return {
isValid: false, isValid: false,
parsed: config.params?.default || {}, parsed: config.params?.default || {},
message: `${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`, messages: [
`${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`,
],
}; };
} }
}, },
@ -565,7 +589,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
const invalidResponse = { const invalidResponse = {
isValid: false, isValid: false,
parsed: config.params?.default || [], parsed: config.params?.default || [],
message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, messages: [`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`],
}; };
if (value === undefined || value === null || value === "") { if (value === undefined || value === null || value === "") {
if ( if (
@ -573,8 +597,9 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
config.params.required && config.params.required &&
!isArray(config.params.default) !isArray(config.params.default)
) { ) {
invalidResponse.message = invalidResponse.messages = [
"This property is required for the widget to function correctly"; "This property is required for the widget to function correctly",
];
return invalidResponse; return invalidResponse;
} }
if (value === "") { if (value === "") {
@ -622,7 +647,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
const invalidResponse = { const invalidResponse = {
isValid: false, isValid: false,
parsed: config.params?.default || [{}], parsed: config.params?.default || [{}],
message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, messages: [`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`],
}; };
if (value === undefined || value === null || value === "") { if (value === undefined || value === null || value === "") {
if (config.params?.required) return invalidResponse; if (config.params?.required) return invalidResponse;
@ -666,7 +691,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
if (!isPlainObject(parsedEntry)) { if (!isPlainObject(parsedEntry)) {
return { return {
...invalidResponse, ...invalidResponse,
message: `Invalid object at index ${index}`, messages: [`Invalid object at index ${index}`],
}; };
} }
} }
@ -683,7 +708,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
let response: ValidationResponse = { let response: ValidationResponse = {
isValid: false, isValid: false,
parsed: config.params?.default || [], parsed: config.params?.default || [],
message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, messages: [`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`],
}; };
response = VALIDATORS.ARRAY(config, value, props); response = VALIDATORS.ARRAY(config, value, props);
@ -702,7 +727,9 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
response = { response = {
...response, ...response,
isValid: false, isValid: false,
message: `Array entry path:${param} must be unique. Duplicate values found`, messages: [
`path:${param} must be unique. Duplicate values found`,
],
}; };
} }
} }
@ -718,7 +745,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
const invalidResponse = { const invalidResponse = {
isValid: false, isValid: false,
parsed: config.params?.default || moment().toISOString(true), parsed: config.params?.default || moment().toISOString(true),
message: `Value does not match: ${getExpectedType(config)}`, messages: [`Value does not match: ${getExpectedType(config)}`],
}; };
if (value === undefined || value === null || !isString(value)) { if (value === undefined || value === null || !isString(value)) {
if (!config.params?.required) { if (!config.params?.required) {
@ -761,7 +788,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
const invalidResponse = { const invalidResponse = {
isValid: false, isValid: false,
parsed: undefined, parsed: undefined,
message: "Failed to validate", messages: ["Failed to validate"],
}; };
if (config.params?.fnString && isString(config.params?.fnString)) { if (config.params?.fnString && isString(config.params?.fnString)) {
try { try {
@ -786,7 +813,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
const invalidResponse = { const invalidResponse = {
isValid: false, isValid: false,
parsed: config.params?.default || "", parsed: config.params?.default || "",
message: `${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`, messages: [`${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`],
}; };
const base64Regex = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/; const base64Regex = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
const base64ImageRegex = /^data:image\/.*;base64/; const base64ImageRegex = /^data:image\/.*;base64/;
@ -822,7 +849,7 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
const invalidResponse = { const invalidResponse = {
isValid: false, isValid: false,
parsed: config?.params?.default || "", parsed: config?.params?.default || "",
message: `${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`, messages: [`${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`],
}; };
if (typeof value === "string" && getIsSafeURL(value)) { if (typeof value === "string" && getIsSafeURL(value)) {