Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
// render the union of all item types
if (schema.isCollectionProperty(propSpec)) {
// render the union of all item types
const itemTypes = genspec.specTypesToCodeTypes(resourceContext, itemTypeNames(propSpec));
// 'tokenizableType' operates at the level of rendered type names in TypeScript, so stringify
// the objects.
const renderedTypes = itemTypes.map(t => this.renderCodeName(resourceContext, t));
if (!tokenizableType(renderedTypes) && propName !== 'Tags') {
// Always accept a token in place of any list element (unless the list elements are tokenizable)
itemTypes.push(genspec.TOKEN_NAME);
}
const union = this.renderTypeUnion(resourceContext, itemTypes);
if (schema.isMapProperty(propSpec)) {
alternatives.push(`{ [key: string]: (${union}) }`);
} else {
// To make TSLint happy, we have to either emit: SingleType[] or Array
if (union.indexOf('|') !== -1) {
alternatives.push(`Array<${union}>`);
} else {
alternatives.push(`${union}[]`);
}
}
}
// Yes, some types can be both collection and scalar. Looking at you, SAM.
if (schema.isScalarPropery(propSpec)) {
// Scalar type
const typeNames = scalarTypeNames(propSpec);
const types = genspec.specTypesToCodeTypes(resourceContext, typeNames);
export function typeDispatch(resourceContext: CodeName, spec: schema.Property, visitor: PropertyVisitor): T {
const scalarTypes = specTypesToCodeTypes(resourceContext, scalarTypeNames(spec));
const itemTypes = specTypesToCodeTypes(resourceContext, itemTypeNames(spec));
if (scalarTypes.length && itemTypes.length) {
// Can accept both a list and a scalar
return visitor.visitListOrScalar(scalarTypes, itemTypes);
} else if (schema.isCollectionProperty(spec)) {
if (schema.isMapProperty(spec)) {
if (itemTypes.length > 1) {
return visitor.visitUnionMap(itemTypes);
} else {
return visitor.visitMap(itemTypes[0]);
}
} else {
if (itemTypes.length > 1) {
return visitor.visitUnionList(itemTypes);
} else {
return visitor.visitList(itemTypes[0]);
}
}
} else {
if (scalarTypes.length > 1) {
return visitor.visitUnionScalar(scalarTypes);
} else {
function _diffProperty(oldV: any, newV: any, key: string, resourceSpec?: cfnspec.schema.ResourceType) {
let changeImpact = types.ResourceImpact.NO_CHANGE;
const spec = resourceSpec && resourceSpec.Properties && resourceSpec.Properties[key];
if (spec && !deepEqual(oldV, newV)) {
switch (spec.UpdateType) {
case cfnspec.schema.UpdateType.Immutable:
changeImpact = types.ResourceImpact.WILL_REPLACE;
break;
case cfnspec.schema.UpdateType.Conditional:
changeImpact = types.ResourceImpact.MAY_REPLACE;
break;
default:
// In those cases, whatever is the current value is what we should keep
changeImpact = types.ResourceImpact.WILL_UPDATE;
}
}
return new types.PropertyDifference(oldV, newV, { changeImpact });
}
private readResourceChange(resourceChange: ResourceChange) {
switch (resourceChange.scrutinyType) {
case cfnspec.schema.ResourceScrutinyType.IdentityPolicyResource:
// AWS::IAM::Policy
this.statements.addOld(...this.readIdentityPolicyResource(resourceChange.oldProperties));
this.statements.addNew(...this.readIdentityPolicyResource(resourceChange.newProperties));
break;
case cfnspec.schema.ResourceScrutinyType.ResourcePolicyResource:
// AWS::*::{Bucket,Queue,Topic}Policy
this.statements.addOld(...this.readResourcePolicyResource(resourceChange.oldProperties));
this.statements.addNew(...this.readResourcePolicyResource(resourceChange.newProperties));
break;
case cfnspec.schema.ResourceScrutinyType.LambdaPermission:
this.statements.addOld(...this.readLambdaStatements(resourceChange.oldProperties));
this.statements.addNew(...this.readLambdaStatements(resourceChange.newProperties));
break;
}
}
private findNativeType(resourceContext: genspec.CodeName, propSpec: schema.Property, propName?: string): string {
const alternatives: string[] = [];
// render the union of all item types
if (schema.isCollectionProperty(propSpec)) {
// render the union of all item types
const itemTypes = genspec.specTypesToCodeTypes(resourceContext, itemTypeNames(propSpec));
// 'tokenizableType' operates at the level of rendered type names in TypeScript, so stringify
// the objects.
const renderedTypes = itemTypes.map(t => this.renderCodeName(resourceContext, t));
if (!tokenizableType(renderedTypes) && propName !== 'Tags') {
// Always accept a token in place of any list element (unless the list elements are tokenizable)
itemTypes.push(genspec.TOKEN_NAME);
}
const union = this.renderTypeUnion(resourceContext, itemTypes);
if (schema.isMapProperty(propSpec)) {
alternatives.push(`{ [key: string]: (${union}) }`);
} else {
export function typeDispatch(resourceContext: CodeName, spec: schema.Property, visitor: PropertyVisitor): T {
const scalarTypes = specTypesToCodeTypes(resourceContext, scalarTypeNames(spec));
const itemTypes = specTypesToCodeTypes(resourceContext, itemTypeNames(spec));
if (scalarTypes.length && itemTypes.length) {
// Can accept both a list and a scalar
return visitor.visitListOrScalar(scalarTypes, itemTypes);
} else if (schema.isCollectionProperty(spec)) {
if (schema.isMapProperty(spec)) {
if (itemTypes.length > 1) {
return visitor.visitUnionMap(itemTypes);
} else {
return visitor.visitMap(itemTypes[0]);
}
} else {
if (itemTypes.length > 1) {
return visitor.visitUnionList(itemTypes);
} else {
return visitor.visitList(itemTypes[0]);
}
}
} else {
if (scalarTypes.length > 1) {
return visitor.visitUnionScalar(scalarTypes);
if (resourceChange.resourceTypeChanged) {
// Treat as DELETE+ADD
if (scrutinizableTypes.has(resourceChange.oldResourceType!)) {
ret.push({
...commonProps,
newProperties: undefined,
resourceType: resourceChange.oldResourceType!,
scrutinyType: cfnspec.resourceSpecification(resourceChange.oldResourceType!).ScrutinyType!,
});
}
if (scrutinizableTypes.has(resourceChange.newResourceType!)) {
ret.push({
...commonProps,
oldProperties: undefined,
resourceType: resourceChange.newResourceType!,
scrutinyType: cfnspec.resourceSpecification(resourceChange.newResourceType!).ScrutinyType!,
});
}
} else {
if (scrutinizableTypes.has(resourceChange.resourceType)) {
ret.push({
...commonProps,
resourceType: resourceChange.resourceType,
scrutinyType: cfnspec.resourceSpecification(resourceChange.resourceType).ScrutinyType!,
});
}
}
}
return ret;
}
}
const union = this.renderTypeUnion(resourceContext, itemTypes);
if (schema.isMapProperty(propSpec)) {
alternatives.push(`{ [key: string]: (${union}) }`);
} else {
// To make TSLint happy, we have to either emit: SingleType[] or Array
if (union.indexOf('|') !== -1) {
alternatives.push(`Array<${union}>`);
} else {
alternatives.push(`${union}[]`);
}
}
}
// Yes, some types can be both collection and scalar. Looking at you, SAM.
if (schema.isScalarPropery(propSpec)) {
// Scalar type
const typeNames = scalarTypeNames(propSpec);
const types = genspec.specTypesToCodeTypes(resourceContext, typeNames);
alternatives.push(this.renderTypeUnion(resourceContext, types));
}
// Only if this property is not of a "tokenizable type" (string, string[],
// number in the future) we add a type union for `cdk.Token`. We rather
// everything to be tokenizable because there are languages that do not
// support union types (i.e. Java, .NET), so we lose type safety if we have
// a union.
if (!tokenizableType(alternatives) && propName !== 'Tags') {
alternatives.push(genspec.TOKEN_NAME.fqn);
}
return alternatives.join(' | ');
}
private scrutinizableResourceChanges(scrutinyTypes: cfnspec.schema.ResourceScrutinyType[]): ResourceChange[] {
const ret = new Array();
const scrutinizableTypes = new Set(cfnspec.scrutinizableResourceTypes(scrutinyTypes));
for (const [resourceLogicalId, resourceChange] of Object.entries(this.resources.changes)) {
if (!resourceChange) { continue; }
const commonProps = {
oldProperties: resourceChange.oldProperties,
newProperties: resourceChange.newProperties,
resourceLogicalId
};
// Even though it's not physically possible in CFN, let's pretend to handle a change of 'Type'.
if (resourceChange.resourceTypeChanged) {
// Treat as DELETE+ADD
if (scrutinizableTypes.has(resourceChange.oldResourceType!)) {
ret.push({
...commonProps,
export function diffResource(oldValue?: types.Resource, newValue?: types.Resource): types.ResourceDifference {
const resourceType = {
oldType: oldValue && oldValue.Type,
newType: newValue && newValue.Type
};
let propertyDiffs: { [key: string]: types.PropertyDifference } = {};
let otherDiffs: { [key: string]: types.Difference } = {};
if (resourceType.oldType !== undefined && resourceType.oldType === resourceType.newType) {
// Only makes sense to inspect deeper if the types stayed the same
const typeSpec = cfnspec.filteredSpecification(resourceType.oldType);
const impl = typeSpec.ResourceTypes[resourceType.oldType];
propertyDiffs = diffKeyedEntities(oldValue!.Properties,
newValue!.Properties,
(oldVal, newVal, key) => _diffProperty(oldVal, newVal, key, impl));
otherDiffs = diffKeyedEntities(oldValue, newValue, _diffOther);
delete otherDiffs.Properties;
}
return new types.ResourceDifference(oldValue, newValue, {
resourceType, propertyDiffs, otherDiffs,
});
function _diffProperty(oldV: any, newV: any, key: string, resourceSpec?: cfnspec.schema.ResourceType) {
let changeImpact = types.ResourceImpact.NO_CHANGE;