UNPKG

graphql-transformer-core

Version:

A framework to transform from GraphQL SDL to AWS cloudFormation.

528 lines • 20.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TransformerContext = exports.TransformerContextMetadata = exports.objectExtension = exports.blankObject = void 0; const graphql_1 = require("graphql"); const graphql_transformer_common_1 = require("graphql-transformer-common"); const blankTemplate_1 = __importDefault(require("./util/blankTemplate")); const defaultSchema_1 = __importDefault(require("./defaultSchema")); function blankObject(name) { return { kind: 'ObjectTypeDefinition', name: { kind: 'Name', value: name, }, fields: [], directives: [], interfaces: [], }; } exports.blankObject = blankObject; function objectExtension(name, fields = []) { return { kind: graphql_1.Kind.OBJECT_TYPE_EXTENSION, name: { kind: 'Name', value: name, }, fields, directives: [], interfaces: [], }; } exports.objectExtension = objectExtension; class TransformerContextMetadata { constructor() { this.metadata = {}; } get(key) { return this.metadata[key]; } set(key, val) { return (this.metadata[key] = val); } has(key) { return Boolean(this.metadata[key] !== undefined); } } exports.TransformerContextMetadata = TransformerContextMetadata; class TransformerContext { constructor(inputSDL, featureFlags) { this.featureFlags = featureFlags; this.template = (0, blankTemplate_1.default)(); this.nodeMap = {}; this.metadata = new TransformerContextMetadata(); this.stackMapping = new Map(); const isInputSDLEmpty = inputSDL.trim().length === 0; if (isInputSDLEmpty) { this.inputDocument = { kind: graphql_1.Kind.DOCUMENT, definitions: [], }; } else { const doc = (0, graphql_1.parse)(inputSDL); for (const def of doc.definitions) { if (def.kind === 'OperationDefinition' || def.kind === 'FragmentDefinition') { throw new Error(`Found a ${def.kind}. Transformers accept only documents consisting of TypeSystemDefinitions.`); } } this.inputDocument = doc; } this.fillNodeMapWithInput(); } fillNodeMapWithInput() { const extensionNodes = []; for (const inputDef of this.inputDocument.definitions) { switch (inputDef.kind) { case graphql_1.Kind.OBJECT_TYPE_DEFINITION: case graphql_1.Kind.SCALAR_TYPE_DEFINITION: case graphql_1.Kind.INTERFACE_TYPE_DEFINITION: case graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION: case graphql_1.Kind.ENUM_TYPE_DEFINITION: case graphql_1.Kind.UNION_TYPE_DEFINITION: { const typeDef = inputDef; if (!this.getType(typeDef.name.value)) { this.addType(typeDef); } break; } case graphql_1.Kind.SCHEMA_DEFINITION: if (!this.getSchema()) { const typeDef = inputDef; this.putSchema(typeDef); } break; case graphql_1.Kind.OBJECT_TYPE_EXTENSION: case graphql_1.Kind.ENUM_TYPE_EXTENSION: case graphql_1.Kind.UNION_TYPE_EXTENSION: case graphql_1.Kind.INTERFACE_TYPE_EXTENSION: case graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION: extensionNodes.push(inputDef); break; case graphql_1.Kind.SCALAR_TYPE_EXTENSION: default: } } for (const ext of extensionNodes) { switch (ext.kind) { case graphql_1.Kind.OBJECT_TYPE_EXTENSION: this.addObjectExtension(ext); break; case graphql_1.Kind.INTERFACE_TYPE_EXTENSION: this.addInterfaceExtension(ext); break; case graphql_1.Kind.UNION_TYPE_EXTENSION: this.addUnionExtension(ext); break; case graphql_1.Kind.ENUM_TYPE_EXTENSION: this.addEnumExtension(ext); break; case graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION: this.addInputExtension(ext); break; case graphql_1.Kind.SCALAR_TYPE_EXTENSION: default: continue; } } if (!this.getSchema()) { this.putSchema(defaultSchema_1.default); } } getTypeDefinitionsOfKind(kind) { const typeDefs = []; for (const key of Object.keys(this.nodeMap)) { const definition = this.nodeMap[key]; if (definition.kind === kind) { typeDefs.push(definition); } } return typeDefs; } mergeResources(resources) { for (const resourceId of Object.keys(resources)) { if (this.template.Resources[resourceId]) { throw new Error(`Conflicting CloudFormation resource logical id: ${resourceId}`); } } this.template.Resources = { ...this.template.Resources, ...resources }; } mergeParameters(params) { for (const parameterName of Object.keys(params)) { if (this.template.Parameters[parameterName]) { throw new Error(`Conflicting CloudFormation parameter name: ${parameterName}`); } } this.template.Parameters = { ...this.template.Parameters, ...params }; } mergeConditions(conditions) { if (!this.template.Conditions) { this.template.Conditions = {}; } for (const conditionName of Object.keys(conditions)) { if (this.template.Conditions[conditionName]) { throw new Error(`Conflicting CloudFormation condition name: ${conditionName}`); } } this.template.Conditions = { ...this.template.Conditions, ...conditions }; } getResource(resource) { return this.template.Resources[resource]; } setResource(key, resource) { this.template.Resources[key] = resource; } setOutput(key, output) { this.template.Outputs[key] = output; } getOutput(key) { return this.template.Outputs[key]; } mergeOutputs(outputs) { for (const outputName of Object.keys(outputs)) { if (this.template.Parameters[outputName]) { throw new Error(`Conflicting CloudFormation parameter name: ${outputName}`); } } this.template.Outputs = { ...this.template.Outputs, ...outputs }; } mergeMappings(mapping) { for (const mappingName of Object.keys(mapping)) { if (this.template.Mappings[mappingName]) { throw new Error(`Conflicting CloudFormation mapping name: ${mappingName}`); } } this.template.Mappings = { ...this.template.Mappings, ...mapping }; } putSchema(obj) { this.nodeMap.__schema = obj; } getSchema() { return this.nodeMap.__schema; } getQueryTypeName() { const schemaNode = this.getSchema(); const queryTypeName = schemaNode.operationTypes.find((op) => op.operation === 'query'); if (queryTypeName && queryTypeName.type && queryTypeName.type.name) { return queryTypeName.type.name.value; } } getQuery() { const queryTypeName = this.getQueryTypeName(); if (queryTypeName) { return this.nodeMap[queryTypeName]; } } getMutationTypeName() { const schemaNode = this.getSchema(); const mutationTypeName = schemaNode.operationTypes.find((op) => op.operation === 'mutation'); if (mutationTypeName && mutationTypeName.type && mutationTypeName.type.name) { return mutationTypeName.type.name.value; } } getMutation() { const mutationTypeName = this.getMutationTypeName(); if (mutationTypeName) { return this.nodeMap[mutationTypeName]; } } getSubscriptionTypeName() { const schemaNode = this.getSchema(); const subscriptionTypeName = schemaNode.operationTypes.find((op) => op.operation === 'subscription'); if (subscriptionTypeName && subscriptionTypeName.type && subscriptionTypeName.type.name) { return subscriptionTypeName.type.name.value; } } getSubscription() { const subscriptionTypeName = this.getSubscriptionTypeName(); if (subscriptionTypeName) { return this.nodeMap[subscriptionTypeName]; } } addType(obj) { if (this.nodeMap[obj.name.value]) { throw new Error(`Conflicting type '${obj.name.value}' found.`); } this.nodeMap[obj.name.value] = obj; } putType(obj) { this.nodeMap[obj.name.value] = obj; } getType(name) { return this.nodeMap[name]; } addObject(obj) { if (this.nodeMap[obj.name.value]) { throw new Error(`Conflicting type '${obj.name.value}' found.`); } this.nodeMap[obj.name.value] = obj; } updateObject(obj) { if (!this.nodeMap[obj.name.value]) { throw new Error(`Type ${obj.name.value} does not exist.`); } this.nodeMap[obj.name.value] = obj; } getObject(name) { if (this.nodeMap[name]) { const node = this.nodeMap[name]; if (node.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION) { return node; } } } addQueryFields(fields) { const queryTypeName = this.getQueryTypeName(); if (queryTypeName) { if (!this.getType(queryTypeName)) { this.addType(blankObject(queryTypeName)); } let queryType = objectExtension(queryTypeName, fields); this.addObjectExtension(queryType); } } addMutationFields(fields) { let mutationTypeName = this.getMutationTypeName(); if (!mutationTypeName) { const mutationNode = this.getMutation(); if (!mutationNode) { const schema = this.getSchema(); const mutationOperation = (0, graphql_transformer_common_1.makeOperationType)('mutation', 'Mutation'); const newSchema = { ...schema, operationTypes: [...schema.operationTypes, mutationOperation], }; this.putSchema(newSchema); mutationTypeName = 'Mutation'; } } if (mutationTypeName) { if (!this.getType(mutationTypeName)) { this.addType(blankObject(mutationTypeName)); } let mutationType = objectExtension(mutationTypeName, fields); this.addObjectExtension(mutationType); } } addSubscriptionFields(fields) { let subscriptionTypeName = this.getSubscriptionTypeName(); if (!subscriptionTypeName) { const subscriptionNode = this.getSubscription(); if (!subscriptionNode) { const schema = this.getSchema(); const subscriptionOperation = (0, graphql_transformer_common_1.makeOperationType)('subscription', 'Subscription'); const newSchema = { ...schema, operationTypes: [...schema.operationTypes, subscriptionOperation], }; this.putSchema(newSchema); subscriptionTypeName = 'Subscription'; } } if (subscriptionTypeName) { if (!this.getType(subscriptionTypeName)) { this.addType(blankObject(subscriptionTypeName)); } let subscriptionType = objectExtension(subscriptionTypeName, fields); this.addObjectExtension(subscriptionType); } } addObjectExtension(obj) { if (!this.nodeMap[obj.name.value]) { throw new Error(`Cannot extend nonexistent type '${obj.name.value}'.`); } const oldNode = this.getObject(obj.name.value); const newDirs = []; const oldDirs = oldNode.directives || []; if (obj.directives) { for (const newDir of obj.directives) { if (Boolean(oldDirs.find((d) => d.name.value === newDir.name.value)) === false) { newDirs.push(newDir); } } } const mergedDirs = [...oldDirs, ...newDirs]; const oldFields = oldNode.fields || []; const oldFieldMap = oldFields.reduce((acc, field) => ({ ...acc, [field.name.value]: field, }), {}); const newFields = obj.fields || []; const mergedFields = [...oldFields]; for (const newField of newFields) { if (oldFieldMap[newField.name.value]) { throw new Error(`Object type extension '${obj.name.value}' cannot redeclare field ${newField.name.value}`); } mergedFields.push(newField); } const oldInterfaces = oldNode.interfaces || []; const oldInterfaceMap = oldInterfaces.reduce((acc, field) => ({ ...acc, [field.name.value]: field, }), {}); const newInterfaces = obj.interfaces || []; const mergedInterfaces = [...oldInterfaces]; for (const newInterface of newInterfaces) { if (oldInterfaceMap[newInterface.name.value]) { throw new Error(`Object type extension '${obj.name.value}' cannot redeclare interface ${newInterface.name.value}`); } mergedInterfaces.push(newInterface); } this.nodeMap[oldNode.name.value] = { ...oldNode, interfaces: mergedInterfaces, directives: mergedDirs, fields: mergedFields, }; } addInputExtension(obj) { if (!this.nodeMap[obj.name.value]) { throw new Error(`Cannot extend nonexistent input '${obj.name.value}'.`); } const oldNode = this.getType(obj.name.value); const newDirs = obj.directives || []; const oldDirs = oldNode.directives || []; const mergedDirs = [...oldDirs, ...newDirs]; const oldFields = oldNode.fields || []; const oldFieldMap = oldFields.reduce((acc, field) => ({ ...acc, [field.name.value]: field, }), {}); const newFields = obj.fields || []; const mergedFields = [...oldFields]; for (const newField of newFields) { if (oldFieldMap[newField.name.value]) { throw new Error(`Input object type extension '${obj.name.value}' cannot redeclare field ${newField.name.value}`); } mergedFields.push(newField); } this.nodeMap[oldNode.name.value] = { ...oldNode, directives: mergedDirs, fields: mergedFields, }; } addInterfaceExtension(obj) { if (!this.nodeMap[obj.name.value]) { throw new Error(`Cannot extend nonexistent interface '${obj.name.value}'.`); } const oldNode = this.getType(obj.name.value); const newDirs = obj.directives || []; const oldDirs = oldNode.directives || []; const mergedDirs = [...oldDirs, ...newDirs]; const oldFields = oldNode.fields || []; const oldFieldMap = oldFields.reduce((acc, field) => ({ ...acc, [field.name.value]: field, }), {}); const newFields = obj.fields || []; const mergedFields = [...oldFields]; for (const newField of newFields) { if (oldFieldMap[newField.name.value]) { throw new Error(`Interface type extension '${obj.name.value}' cannot redeclare field ${newField.name.value}`); } mergedFields.push(newField); } this.nodeMap[oldNode.name.value] = { ...oldNode, directives: mergedDirs, fields: mergedFields, }; } addUnionExtension(obj) { if (!this.nodeMap[obj.name.value]) { throw new Error(`Cannot extend nonexistent union '${obj.name.value}'.`); } const oldNode = this.getType(obj.name.value); const newDirs = obj.directives || []; const oldDirs = oldNode.directives || []; const mergedDirs = [...oldDirs, ...newDirs]; const oldTypes = oldNode.types || []; const oldTypeMap = oldTypes.reduce((acc, type) => ({ ...acc, [type.name.value]: true, }), {}); const newTypes = obj.types || []; const mergedFields = [...oldTypes]; for (const newType of newTypes) { if (oldTypeMap[newType.name.value]) { throw new Error(`Union type extension '${obj.name.value}' cannot redeclare type ${newType.name.value}`); } mergedFields.push(newType); } this.nodeMap[oldNode.name.value] = { ...oldNode, directives: mergedDirs, types: mergedFields, }; } addEnumExtension(obj) { if (!this.nodeMap[obj.name.value]) { throw new Error(`Cannot extend nonexistent enum '${obj.name.value}'.`); } const oldNode = this.getType(obj.name.value); const newDirs = obj.directives || []; const oldDirs = oldNode.directives || []; const mergedDirs = [...oldDirs, ...newDirs]; const oldValues = oldNode.values || []; const oldValuesMap = oldValues.reduce((acc, type) => ({ ...acc, [type.name.value]: true, }), {}); const newValues = obj.values || []; const mergedValues = [...oldValues]; for (const newValue of newValues) { if (oldValuesMap[newValue.name.value]) { throw new Error(`Enum type extension '${obj.name.value}' cannot redeclare value ${newValue.name.value}`); } mergedValues.push(newValue); } this.nodeMap[oldNode.name.value] = { ...oldNode, directives: mergedDirs, values: mergedValues, }; } addInput(inp) { if (this.nodeMap[inp.name.value]) { throw new Error(`Conflicting input type '${inp.name.value}' found.`); } this.nodeMap[inp.name.value] = inp; } addEnum(en) { if (this.nodeMap[en.name.value]) { throw new Error(`Conflicting enum type '${en.name.value}' found.`); } this.nodeMap[en.name.value] = en; } mapResourceToStack(stackName, resource) { this.stackMapping.set(resource, stackName); } getStackMapping() { return this.stackMapping; } setResolverConfig(resolverConfig) { if (this.resolverConfig) { throw new Error(`Resolver Configuration has already been added to the context`); } this.resolverConfig = resolverConfig; } getResolverConfig() { return this.resolverConfig; } setTransformerVersion(version) { this.transformerVersion = version; } getTransformerVersion() { return this.transformerVersion; } isProjectUsingDataStore() { return this.resolverConfig && (typeof this.resolverConfig.project !== undefined || typeof this.resolverConfig.models !== undefined); } } exports.TransformerContext = TransformerContext; //# sourceMappingURL=TransformerContext.js.map