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; } } |