Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 1x 1x 1x 1x | import * as fastJsonPatch from 'fast-json-patch';
import { schema } from '../lib';
import { detectScrutinyTypes } from './scrutiny';
export function massageSpec(spec: schema.Specification) {
detectScrutinyTypes(spec);
replaceIncompleteTypes(spec);
dropTypelessAttributes(spec);
}
export function forEachSection(spec: schema.Specification, data: any, cb: (spec: any, fragment: any, path: string[]) => void) {
cb(spec.PropertyTypes, data.PropertyTypes, ['PropertyTypes']);
cb(spec.ResourceTypes, data.ResourceTypes, ['ResourceTypes']);
// Per-resource specs are keyed on ResourceType (singular), but we want it in ResourceTypes (plural)
cb(spec.ResourceTypes, data.ResourceType, ['ResourceType']);
}
export function decorateResourceTypes(data: any) {
const requiredTransform = data.ResourceSpecificationTransform as string | undefined;
Iif (!requiredTransform) { return; }
const resourceTypes = data.ResourceTypes || data.ResourceType;
for (const name of Object.keys(resourceTypes)) {
resourceTypes[name].RequiredTransform = requiredTransform;
}
}
/**
* Fix incomplete type definitions in PropertyTypes
*
* Some user-defined types are defined to not have any properties, and not
* be a collection of other types either. They have no definition at all.
*
* Add a property object type with empty properties.
*/
function replaceIncompleteTypes(spec: schema.Specification) {
for (const [name, definition] of Object.entries(spec.PropertyTypes)) {
Iif (!schema.isRecordType(definition)
&& !schema.isCollectionProperty(definition)
&& !schema.isScalarProperty(definition)
&& !schema.isPrimitiveProperty(definition)) {
// eslint-disable-next-line no-console
console.log(`[${name}] Incomplete type, adding empty "Properties" field`);
(definition as unknown as schema.RecordProperty).Properties = {};
}
}
}
/**
* Drop Attributes specified with the different ResourceTypes that have
* no type specified.
*/
function dropTypelessAttributes(spec: schema.Specification) {
const resourceTypes = spec.ResourceTypes;
Object.values(resourceTypes).forEach((resourceType) => {
const attributes = resourceType.Attributes ?? {};
Object.keys(attributes).forEach((attrKey) => {
const attrVal = attributes[attrKey];
if (Object.keys(attrVal).length === 0) {
delete attributes[attrKey];
}
});
});
}
export function merge(spec: any, fragment: any, jsonPath: string[]) {
Iif (!fragment) { return; }
for (const key of Object.keys(fragment)) {
if (key in spec) {
const specVal = spec[key];
const fragVal = fragment[key];
Iif (typeof specVal !== typeof fragVal) {
// eslint-disable-next-line max-len
throw new Error(`Attempted to merge ${JSON.stringify(fragVal)} into incompatible ${JSON.stringify(specVal)} at path ${jsonPath.join('/')}/${key}`);
}
Iif (typeof specVal !== 'object') {
// eslint-disable-next-line max-len
throw new Error(`Conflict when attempting to merge ${JSON.stringify(fragVal)} into ${JSON.stringify(specVal)} at path ${jsonPath.join('/')}/${key}`);
}
merge(specVal, fragVal, [...jsonPath, key]);
} else {
spec[key] = fragment[key];
}
}
}
export function patch(spec: any, fragment: any) {
Iif (!fragment) { return; }
if ('patch' in fragment) {
// eslint-disable-next-line no-console
console.log(`Applying patch: ${fragment.patch.description}`);
fastJsonPatch.applyPatch(spec, fragment.patch.operations);
} else {
for (const key of Object.keys(fragment)) {
patch(spec[key], fragment[key]);
}
}
}
/**
* Modifies the provided specification so that ``ResourceTypes`` and ``PropertyTypes`` are listed in alphabetical order.
*
* @param spec an AWS CloudFormation Resource Specification document.
*
* @returns ``spec``, after having sorted the ``ResourceTypes`` and ``PropertyTypes`` sections alphabetically.
*/
export function normalize(spec: schema.Specification): schema.Specification {
spec.ResourceTypes = normalizeSection(spec.ResourceTypes);
Iif (spec.PropertyTypes) {
spec.PropertyTypes = normalizeSection(spec.PropertyTypes);
}
return spec;
function normalizeSection<T>(section: { [name: string]: T }): { [name: string]: T } {
const result: { [name: string]: T } = {};
for (const key of Object.keys(section).sort()) {
result[key] = section[key];
}
return result;
}
}
|