in src/declarative-stack.ts [119:234]
function deserializeValue(stack: cdk.Stack, typeRef: reflect.TypeReference, optional: boolean, key: string, value: any): any {
// console.error('====== deserializer ===================');
// console.error(`type: ${typeRef}`);
// console.error(`value: ${JSON.stringify(value, undefined, 2)}`);
// console.error('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`');
if (value === undefined) {
if (optional) {
return undefined;
}
throw new Error(`Missing required value for ${key} in ${typeRef}`);
}
// deserialize arrays
if (typeRef.arrayOfType) {
if (!Array.isArray(value)) {
throw new Error(`Expecting array for ${key} in ${typeRef}`);
}
return value.map((x, i) => deserializeValue(stack, typeRef.arrayOfType!, false, `${key}[${i}]`, x));
}
const asRef = tryResolveRef(value);
if (asRef) {
if (isConstruct(typeRef)) {
return findConstruct(stack, value.Ref);
}
throw new Error(
`{ Ref } can only be used when a construct type is expected and this is ${typeRef}. ` +
'Use { Fn::GetAtt } to represent specific resource attributes');
}
const getAtt = tryResolveGetAtt(value);
if (getAtt) {
const [logical, attr] = getAtt;
if (isConstruct(typeRef)) {
const obj: any = findConstruct(stack, logical);
return obj[attr];
}
if (typeRef.primitive === 'string') {
// return a lazy value, so we only try to find after all constructs
// have been added to the stack.
return deconstructGetAtt(stack, logical, attr);
}
throw new Error(`Fn::GetAtt can only be used for string primitives and ${key} is ${typeRef}`);
}
// deserialize maps
if (typeRef.mapOfType) {
if (typeof(value) !== 'object') {
throw new ValidationError(`Expecting object for ${key} in ${typeRef}`);
}
const out: any = { };
for (const [k, v] of Object.entries(value)) {
out[k] = deserializeValue(stack, typeRef.mapOfType, false, `${key}.${k}`, v);
}
return out;
}
if (typeRef.unionOfTypes) {
const errors = new Array<any>();
for (const x of typeRef.unionOfTypes) {
try {
return deserializeValue(stack, x, optional, key, value);
} catch (e) {
if (!(e instanceof ValidationError)) {
throw e;
}
errors.push(e);
continue;
}
}
throw new ValidationError(`Failed to deserialize union. Errors: \n ${errors.map(e => e.message).join('\n ')}`);
}
const enm = deconstructEnum(stack, typeRef, key, value);
if (enm) {
return enm;
}
// if this is an interface, deserialize each property
const ifc = deconstructInterface(stack, typeRef, key, value);
if (ifc) {
return ifc;
}
// if this is an enum type, use the name to dereference
if (typeRef.type instanceof reflect.EnumType) {
const enumType = resolveType(typeRef.type.fqn);
return enumType[value];
}
if (typeRef.primitive) {
return value;
}
const enumLike = deconstructEnumLike(stack, typeRef, value);
if (enumLike) {
return enumLike;
}
const asType = deconstructType(stack, typeRef, value);
if (asType) {
return asType;
}
throw new Error(`Unable to deconstruct "${JSON.stringify(value)}" for type ref ${typeRef}`);
}