zoid
Version:
Cross domain components.
165 lines (128 loc) • 5.92 kB
JavaScript
/* @flow */
import { ZalgoPromise } from 'zalgo-promise/src';
import { dotify, isDefined, base64encode, noop } from 'belter/src';
import { eachProp, mapProps, type PropsInputType, type PropsType, type PropsDefinitionType } from '../component/props';
import { PROP_SERIALIZATION, METHOD, PROP_TYPE } from '../constants';
import type { ParentHelpers } from './index';
export function extendProps<P, X>(propsDef : PropsDefinitionType<P, X>, existingProps : PropsType<P>, inputProps : PropsInputType<P>, helpers : ParentHelpers<P>, container : HTMLElement | void) {
const { state, close, focus, event, onError } = helpers;
// $FlowFixMe
eachProp(inputProps, propsDef, (key, propDef, val) => {
let valueDetermined = false;
let value = val;
const getDerivedValue = () => {
if (!propDef) {
return value;
}
const alias = propDef.alias;
if (alias && !isDefined(val) && isDefined(inputProps[alias])) {
value = inputProps[alias];
}
if (propDef.value) {
value = propDef.value({ props: existingProps, state, close, focus, event, onError, container });
}
if (propDef.default && !isDefined(value) && !isDefined(inputProps[key])) {
value = propDef.default({ props: existingProps, state, close, focus, event, onError, container });
}
if (isDefined(value)) {
if (propDef.type === PROP_TYPE.ARRAY ? !Array.isArray(value) : (typeof value !== propDef.type)) {
throw new TypeError(`Prop is not of type ${ propDef.type }: ${ key }`);
}
} else {
if (propDef.required !== false && !isDefined(inputProps[key])) {
throw new Error(`Expected prop "${ key }" to be defined`);
}
}
if (__DEBUG__ && isDefined(value) && propDef.validate) {
// $FlowFixMe
propDef.validate({ value, props: inputProps });
}
if (isDefined(value) && propDef.decorate) {
// $FlowFixMe
value = propDef.decorate({ value, props: existingProps, state, close, focus, event, onError, container });
}
return value;
};
const getter = () => {
if (valueDetermined) {
return value;
}
valueDetermined = true;
return getDerivedValue();
};
Object.defineProperty(existingProps, key, {
configurable: true,
enumerable: true,
get: getter
});
});
// $FlowFixMe
eachProp(existingProps, propsDef, noop);
}
export function serializeProps<P, X>(propsDef : PropsDefinitionType<P, X>, props : (PropsType<P>), method : $Values<typeof METHOD>) : ZalgoPromise<{ [string] : string | boolean }> {
const params = {};
return ZalgoPromise.all(mapProps(props, propsDef, (key, propDef, value) => {
return ZalgoPromise.resolve().then(() => {
if (value === null || typeof value === 'undefined' || !propDef) {
return;
}
const getParam = {
[ METHOD.GET ]: propDef.queryParam,
[ METHOD.POST ]: propDef.bodyParam
}[method];
const getValue = {
[ METHOD.GET ]: propDef.queryValue,
[ METHOD.POST ]: propDef.bodyValue
}[method];
if (!getParam) {
return;
}
return ZalgoPromise.hash({
finalParam: ZalgoPromise.try(() => {
if (typeof getParam === 'function') {
// $FlowFixMe[incompatible-call]
return getParam({ value });
} else if (typeof getParam === 'string') {
return getParam;
} else {
return key;
}
}),
finalValue: ZalgoPromise.try(() => {
if (typeof getValue === 'function' && isDefined(value)) {
// $FlowFixMe[incompatible-call]
// $FlowFixMe[incompatible-return]
return getValue({ value });
} else {
// $FlowFixMe[incompatible-return]
return value;
}
})
}).then(({ finalParam, finalValue }) => {
let result;
if (typeof finalValue === 'boolean') {
result = finalValue.toString();
} else if (typeof finalValue === 'string') {
result = finalValue.toString();
} else if (typeof finalValue === 'object' && finalValue !== null) {
if (propDef.serialization === PROP_SERIALIZATION.JSON) {
result = JSON.stringify(finalValue);
} else if (propDef.serialization === PROP_SERIALIZATION.BASE64) {
result = base64encode(JSON.stringify(finalValue));
} else if (propDef.serialization === PROP_SERIALIZATION.DOTIFY || !propDef.serialization) {
result = dotify(finalValue, key);
for (const dotkey of Object.keys(result)) {
params[dotkey] = result[dotkey];
}
return;
}
} else if (typeof finalValue === 'number') {
result = finalValue.toString();
}
params[finalParam] = result;
});
});
})).then(() => {
return params;
});
}