budibase/packages/builder/src/userInterface/pagesParsing/createProps.js

170 lines
4.3 KiB
JavaScript

import {
isString,
isUndefined,
find,
keys,
uniq,
some,
filter,
reduce,
cloneDeep,
includes
} from "lodash/fp";
import { types, expandPropsDefinition } from "./types";
import { assign } from "lodash";
import { pipe } from "../../common/core";
import { isRootComponent } from "./searchComponents";
export const createPropDefinitionForDerived = (allComponents, componentName) => {
const {propDef, derivedProps} = getComponentInfo(allComponents, componentName);
const hasDerivedProp = k => pipe(derivedProps, [
keys,
uniq,
some(key => key === k)
]);
return pipe(propDef, [
keys,
filter(k => !hasDerivedProp(k)),
reduce((obj, k) => {
obj[k] = propDef[k];
return obj;
}, {}),
expandPropsDefinition
])
}
export const traverseForProps = getComponentInfo;
export const getFinalProps = (componentInfo, props) => {
const finalProps = cloneDeep(componentInfo.fullProps);
for(let p in props) {
finalProps[p] = props[p];
}
return finalProps;
}
export const getNewComponentInfo = (allComponents, inherits) => {
const parentcomponent = find(c => c.name === inherits)(allComponents);
const component = {
name:"",
description:"",
inherits,
props:{},
tags:parentcomponent.tags
};
return getComponentInfo(
allComponents,
inherits,
[component],
{});
}
export const getComponentInfo = (allComponents, cname, stack=[], subComponentProps=null) => {
const component = find(c => c.name === cname)(allComponents);
if(isRootComponent(component)) {
subComponentProps = subComponentProps||{};
const p = createProps(cname, component.props, subComponentProps);
const inheritedProps = [];
if(stack.length > 0) {
const targetComponent = stack[0];
for(let prop in subComponentProps) {
const hasProp = pipe(targetComponent.props, [
keys,
includes(prop)]);
if(!hasProp)
inheritedProps.push(prop);
}
}
const unsetProps = pipe(p.props, [
keys,
filter(k => !includes(k)(keys(subComponentProps)))
]);
return ({
propsDefinition:component.props,
inheritedProps,
rootDefaultProps: p.props,
unsetProps,
fullProps: p.props,
errors: p.errors,
component: stack.length > 0 ? stack[0] : component
});
}
return getComponentInfo(
allComponents,
component.inherits,
[...stack, component],
{...component.props, ...subComponentProps});
}
export const createProps = (componentName, propsDefinition, derivedFromProps) => {
const error = (propName, error) =>
errors.push({propName, error});
const props = {
_component: componentName
};
const errors = [];
if(!componentName)
error("_component", "Component name not supplied");
for(let propDef in propsDefinition) {
const parsedPropDef = parsePropDef(propsDefinition[propDef]);
if(parsedPropDef.error)
error(propDef, parsedPropDef.error);
else
props[propDef] = parsedPropDef;
}
if(derivedFromProps) {
assign(props, derivedFromProps);
}
return ({
props, errors
});
}
const parsePropDef = propDef => {
const error = message => ({error:message, propDef});
if(isString(propDef)) {
if(!types[propDef])
return error(`Do not recognise type ${propDef}`);
return types[propDef].default();
}
if(!propDef.type)
return error("Property Definition must declare a type");
const type = types[propDef.type];
if(!type)
return error(`Do not recognise type ${propDef.type}`);
if(isUndefined(propDef.default))
return type.default(propDef);
if(!type.isOfType(propDef.default))
return error(`${propDef.default} is not of type ${type}`);
return propDef.default;
}
/*
Allowed propDefOptions
- type: string, bool, number, array
- default: default value, when undefined
- required: field is required
*/