forked from tsai/budibase
4 changed files with 272 additions and 0 deletions
@ -0,0 +1,12 @@ |
|||
{ |
|||
"presets": ["@babel/preset-env"], |
|||
"sourceMaps": "inline", |
|||
"retainLines": true, |
|||
"plugins": [ |
|||
["@babel/plugin-transform-runtime", |
|||
{ |
|||
"regenerator": true |
|||
} |
|||
] |
|||
] |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
import { |
|||
isString, |
|||
isBoolean, |
|||
isNumber, |
|||
isArray, |
|||
isUndefined |
|||
} from "lodash/fp"; |
|||
|
|||
import { assign } from "lodash"; |
|||
|
|||
export const createDefaultProps = (propsDefinition, derivedFromProps) => { |
|||
|
|||
const props = {}; |
|||
const errors = []; |
|||
|
|||
for(let propDef in propsDefinition) { |
|||
const parsedPropDef = parsePropDef(propsDefinition[propDef]); |
|||
if(parsedPropDef.error) |
|||
errors.push({propName:propDef, error:parsedPropDef.error}); |
|||
else |
|||
props[propDef] = parsedPropDef; |
|||
} |
|||
|
|||
if(derivedFromProps) { |
|||
assign(props, ...derivedFromProps); |
|||
} |
|||
|
|||
return ({ |
|||
props, errors |
|||
}); |
|||
} |
|||
|
|||
const parsePropDef = propDef => { |
|||
const error = message => ({error:message}); |
|||
|
|||
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; |
|||
} |
|||
|
|||
const propType = (defaultValue, isOfType) => ({ |
|||
isOfType, default:defaultValue |
|||
}); |
|||
|
|||
const types = { |
|||
string: propType(() => "", isString), |
|||
bool: propType(() => false, isBoolean), |
|||
number: propType(() => 0, isNumber), |
|||
array: propType(() => [], isArray) |
|||
} |
|||
@ -0,0 +1,162 @@ |
|||
import { createDefaultProps } from "../src/userInterface/propsDefinitionParsing/createDefaultProps"; |
|||
import { |
|||
keys, some |
|||
} from "lodash/fp"; |
|||
|
|||
describe("createDefaultProps", () => { |
|||
|
|||
it("should create a object with single string value, when default string field set", () => { |
|||
const propDef = { |
|||
fieldName: {type:"string", default:"something"} |
|||
}; |
|||
|
|||
const { props, errors } = createDefaultProps(propDef); |
|||
|
|||
expect(errors).toEqual([]); |
|||
expect(props.fieldName).toBeDefined(); |
|||
expect(props.fieldName).toBe("something"); |
|||
expect(keys(props).length).toBe(1); |
|||
}); |
|||
|
|||
it("should create a object with single blank string value, when no default", () => { |
|||
const propDef = { |
|||
fieldName: {type:"string"} |
|||
}; |
|||
|
|||
const { props, errors } = createDefaultProps(propDef); |
|||
|
|||
expect(errors).toEqual([]); |
|||
expect(props.fieldName).toBeDefined(); |
|||
expect(props.fieldName).toBe(""); |
|||
}); |
|||
|
|||
it("should create a object with single blank string value, when prop definition is 'string' ", () => { |
|||
const propDef = { |
|||
fieldName: "string" |
|||
}; |
|||
|
|||
const { props, errors } = createDefaultProps(propDef); |
|||
|
|||
expect(errors).toEqual([]); |
|||
expect(props.fieldName).toBeDefined(); |
|||
expect(props.fieldName).toBe(""); |
|||
}); |
|||
|
|||
it("should create a object with single fals value, when prop definition is 'bool' ", () => { |
|||
const propDef = { |
|||
fieldName: "bool" |
|||
}; |
|||
|
|||
const { props, errors } = createDefaultProps(propDef); |
|||
|
|||
expect(errors).toEqual([]); |
|||
expect(props.fieldName).toBeDefined(); |
|||
expect(props.fieldName).toBe(false); |
|||
}); |
|||
|
|||
it("should create a object with single 0 value, when prop definition is 'number' ", () => { |
|||
const propDef = { |
|||
fieldName: "number" |
|||
}; |
|||
|
|||
const { props, errors } = createDefaultProps(propDef); |
|||
|
|||
expect(errors).toEqual([]); |
|||
expect(props.fieldName).toBeDefined(); |
|||
expect(props.fieldName).toBe(0); |
|||
}); |
|||
|
|||
it("should create a object with single 0 value, when prop definition is 'array' ", () => { |
|||
const propDef = { |
|||
fieldName: "array" |
|||
}; |
|||
|
|||
const { props, errors } = createDefaultProps(propDef); |
|||
|
|||
expect(errors).toEqual([]); |
|||
expect(props.fieldName).toBeDefined(); |
|||
expect(props.fieldName).toEqual([]); |
|||
}); |
|||
|
|||
it("should create an object with multiple prop names", () => { |
|||
const propDef = { |
|||
fieldName: "string", |
|||
fieldLength: { type: "number", default: 500 } |
|||
}; |
|||
|
|||
const { props, errors } = createDefaultProps(propDef); |
|||
|
|||
expect(errors).toEqual([]); |
|||
expect(props.fieldName).toBeDefined(); |
|||
expect(props.fieldName).toBe(""); |
|||
expect(props.fieldLength).toBeDefined(); |
|||
expect(props.fieldLength).toBe(500); |
|||
expect(keys(props).length).toBe(2); |
|||
}) |
|||
|
|||
it("should return error when invalid type", () => { |
|||
const propDef = { |
|||
fieldName: "invalid type name", |
|||
fieldLength: { type: "invalid type name "} |
|||
}; |
|||
|
|||
const { errors } = createDefaultProps(propDef); |
|||
|
|||
expect(errors.length).toBe(2); |
|||
expect(some(e => e.propName === "fieldName")(errors)).toBeTruthy(); |
|||
expect(some(e => e.propName === "fieldLength")(errors)).toBeTruthy(); |
|||
}); |
|||
|
|||
it("should return error default value is not of declared type", () => { |
|||
const propDef = { |
|||
fieldName: {type:"string", default: 1} |
|||
}; |
|||
|
|||
const { errors } = createDefaultProps(propDef); |
|||
|
|||
expect(errors.length).toBe(1); |
|||
expect(some(e => e.propName === "fieldName")(errors)).toBeTruthy(); |
|||
}); |
|||
|
|||
it("should merge in derived props", () => { |
|||
const propDef = { |
|||
fieldName: "string", |
|||
fieldLength: { type: "number", default: 500} |
|||
}; |
|||
|
|||
const derivedFrom = { |
|||
fieldName: "surname" |
|||
}; |
|||
|
|||
const { props, errors } = createDefaultProps(propDef, [derivedFrom]); |
|||
|
|||
expect(errors.length).toBe(0); |
|||
expect(props.fieldName).toBe("surname"); |
|||
expect(props.fieldLength).toBe(500); |
|||
|
|||
}); |
|||
|
|||
it("should merge in derived props, last in list taking priority", () => { |
|||
const propDef = { |
|||
fieldName: "string", |
|||
fieldLength: { type: "number", default: 500} |
|||
}; |
|||
|
|||
const derivedFrom1 = { |
|||
fieldName: "surname", |
|||
fieldLength: 200 |
|||
}; |
|||
|
|||
const derivedFrom2 = { |
|||
fieldName: "forename" |
|||
}; |
|||
|
|||
const { props, errors } = createDefaultProps(propDef, [derivedFrom1, derivedFrom2]); |
|||
|
|||
expect(errors.length).toBe(0); |
|||
expect(props.fieldName).toBe("forename"); |
|||
expect(props.fieldLength).toBe(200); |
|||
|
|||
}); |
|||
|
|||
}) |
|||
Loading…
Reference in new issue