mirror of https://github.com/Budibase/budibase.git
nocodelowcodelow-codedockerdocker-composeinternal-projectinternal-toolinternal-toolslow-code-developmentlow-code-development-platformopensourceselfhostedweb-devweb-developmentweb-development-toolswebdevwebdevelopmentworkflow-automationautomationdeveloper-tools
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
3.8 KiB
143 lines
3.8 KiB
import { types } from "./types";
|
|
import {
|
|
createProps, arrayElementComponentName
|
|
} from "./createProps";
|
|
import { isString } from "util";
|
|
import {
|
|
includes, filter, map, keys,
|
|
flatten, flattenDeep, each,
|
|
indexOf, isUndefined
|
|
} from "lodash/fp";
|
|
import { common } from "../../../../core/src";
|
|
import {
|
|
isBinding
|
|
} from "../../common/binding";
|
|
|
|
const pipe = common.$;
|
|
|
|
const makeError = (errors, propName, stack) => (message) =>
|
|
errors.push({
|
|
stack,
|
|
propName,
|
|
error: message
|
|
});
|
|
|
|
export const recursivelyValidate = (rootProps, getComponent, stack = []) => {
|
|
|
|
if (!rootProps._component) {
|
|
const errs = [];
|
|
makeError(errs, "_component", stack)("Component is not set");
|
|
return errs;
|
|
// this would break everything else anyway
|
|
}
|
|
|
|
const componentDef = getComponent(
|
|
rootProps._component);
|
|
|
|
|
|
const errors = validateProps(
|
|
componentDef,
|
|
rootProps,
|
|
stack,
|
|
true);
|
|
|
|
const validateChildren = (_props, _stack) =>
|
|
!_props._children
|
|
? []
|
|
: pipe(_props._children, [
|
|
map(child => recursivelyValidate(
|
|
child,
|
|
getComponent,
|
|
[..._stack, _props._children.indexOf(child)]))
|
|
]);
|
|
|
|
const childErrors = validateChildren(
|
|
rootProps, stack);
|
|
|
|
return flattenDeep([errors, ...childErrors]);
|
|
}
|
|
|
|
const expandPropDef = propDef =>
|
|
isString(propDef)
|
|
? types[propDef].defaultDefinition()
|
|
: propDef;
|
|
|
|
|
|
|
|
export const validateProps = (componentDefinition, props, stack = [], isFinal = true) => {
|
|
|
|
const errors = [];
|
|
|
|
if (isFinal && !props._component) {
|
|
makeError(errors, "_component", stack)("Component is not set");
|
|
return errors;
|
|
// this would break everything else anyway
|
|
}
|
|
|
|
const propsDefinition = componentDefinition.props;
|
|
|
|
for (let propDefName in props) {
|
|
|
|
const ignore = ['_component', "_children", '_layout', 'name', 'description', 'location'];
|
|
|
|
if (ignore.includes(propDefName)) continue;
|
|
|
|
const propDef = expandPropDef(propsDefinition[propDefName]);
|
|
|
|
const type = types[propDef.type];
|
|
|
|
const error = makeError(errors, propDefName, stack);
|
|
|
|
const propValue = props[propDefName];
|
|
|
|
// component declarations dont need to define al props.
|
|
if (!isFinal && isUndefined(propValue)) continue;
|
|
|
|
if (isFinal && propDef.required && propValue) {
|
|
error(`Property ${propDefName} is required`);
|
|
continue;
|
|
}
|
|
|
|
if (isBinding(propValue)) {
|
|
if (propDef.type === "event") {
|
|
error(`Cannot apply binding to type ${propDef.type}`);
|
|
continue;
|
|
}
|
|
}
|
|
else if (!type.isOfType(propValue)) {
|
|
error(`Property ${propDefName} is not of type ${propDef.type}. Actual value ${propValue}`)
|
|
continue;
|
|
}
|
|
|
|
|
|
if (propDef.type === "options"
|
|
&& propValue
|
|
&& !isBinding(propValue)
|
|
&& !includes(propValue)(propDef.options)) {
|
|
error(`Property ${propDefName} is not one of allowed options. Acutal value is ${propValue}`);
|
|
}
|
|
|
|
}
|
|
|
|
return errors;
|
|
}
|
|
|
|
export const validateComponentDefinition = (componentDefinition) => {
|
|
const { errors } = createProps(componentDefinition);
|
|
|
|
const propDefinitions = expandPropDef(componentDefinition.props);
|
|
|
|
pipe(propDefinitions, [
|
|
keys,
|
|
map(k => ({
|
|
propDef: propDefinitions[k],
|
|
propName: k
|
|
})),
|
|
filter(d => d.propDef.type === "options"
|
|
&& (!d.propDef.options || d.propDef.options.length === 0)),
|
|
each(d => makeError(errors, d.propName)(`${d.propName} does not have any options`))
|
|
]);
|
|
|
|
return errors;
|
|
|
|
}
|
|
|