@aws-amplify/graphql-types-generator
Version:
Generate API code or type annotations based on a GraphQL schema and statements
298 lines • 13.1 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.propertyFromVar = exports.variablesFromField = exports.generateSource = void 0;
const graphql_1 = require("graphql");
const prettier = require("prettier");
const CodeGenerator_1 = require("../utilities/CodeGenerator");
const codeGeneration_1 = require("../typescript/codeGeneration");
const types_1 = require("../typescript/types");
const language_1 = require("../typescript/language");
const graphql_2 = require("../utilities/graphql");
const codeGeneration_2 = require("../flow/codeGeneration");
function generateSource(context, options) {
var _a;
const isAngularV6 = (_a = options === null || options === void 0 ? void 0 : options.isAngularV6) !== null && _a !== void 0 ? _a : false;
const importApiStatement = isAngularV6
? `import { Client, generateClient, GraphQLResult } from 'aws-amplify/api';`
: `import API, { graphqlOperation, GraphQLResult } from '@aws-amplify/api-graphql';`;
const importObservable = isAngularV6
? `import { Observable } from 'rxjs';`
: `import { Observable } from 'zen-observable-ts';`;
const generator = new CodeGenerator_1.CodeGenerator(context);
generator.printOnNewline('/* tslint:disable */');
generator.printOnNewline('/* eslint-disable */');
generator.printOnNewline('// This file was automatically generated and should not be edited.');
generator.printOnNewline(`import { Injectable } from '@angular/core';`);
generator.printOnNewline(importApiStatement);
generator.printOnNewline(importObservable);
generator.printNewline();
generateTypes(generator, context, { isAngularV6 });
generator.printNewline();
generateAngularService(generator, context, { isAngularV6 });
return prettier.format(generator.output, { parser: 'typescript' });
}
exports.generateSource = generateSource;
function generateTypes(generator, context, options) {
var _a;
const isAngularV6 = (_a = options === null || options === void 0 ? void 0 : options.isAngularV6) !== null && _a !== void 0 ? _a : false;
if (context.schema.getSubscriptionType()) {
if (!isAngularV6) {
generateSubscriptionResponseWrapper(generator);
}
generateSubscriptionOperationTypes(generator, context);
}
context.typesUsed.forEach(type => (0, codeGeneration_1.typeDeclarationForGraphQLType)(generator, type));
Object.values(context.operations).forEach(operation => {
interfaceDeclarationForOperation(generator, operation);
});
Object.values(context.fragments).forEach(operation => (0, codeGeneration_1.interfaceDeclarationForFragment)(generator, operation));
}
function generateSubscriptionResponseWrapper(generator) {
generator.printOnNewline(`
export interface SubscriptionResponse<T> {
value: GraphQLResult<T>;
}`);
generator.printNewline();
}
function generateSubscriptionOperationTypes(generator, context) {
const typeName = '__SubscriptionContainer';
const properties = [];
Object.values(context.operations)
.filter(operation => operation.operationType === 'subscription')
.forEach(operation => {
const { operationName, operationType } = operation;
const typeName = (0, codeGeneration_1.interfaceNameFromOperation)({ operationName, operationType });
if (operation.fields.length) {
properties.push({
fieldName: operation.fields[0].responseName,
typeName,
});
}
});
if (properties.length) {
generator.printOnNewline(`export type ${typeName} = `);
generator.pushScope({ typeName });
generator.withinBlock(() => (0, codeGeneration_2.propertyDeclarations)(generator, properties), '{', '}');
generator.popScope();
generator.print(';');
generator.printNewline();
}
}
function interfaceDeclarationForOperation(generator, { operationName, operationType, fields }) {
const interfaceName = (0, codeGeneration_1.interfaceNameFromOperation)({ operationName, operationType });
fields = fields.map(field => (0, codeGeneration_1.updateTypeNameField)(field));
if (fields[0].fields) {
const properties = (0, codeGeneration_1.propertiesFromFields)(generator.context, fields[0].fields);
(0, language_1.interfaceDeclaration)(generator, {
interfaceName,
}, () => {
(0, codeGeneration_1.pickedPropertyDeclarations)(generator, properties);
});
}
}
function getOperationResultField(operation) {
if (operation.fields.length) {
return operation.fields[0];
}
}
function getReturnTypeName(generator, op) {
const { operationName, operationType } = op;
const { type } = op.fields[0];
if ((0, graphql_1.isListType)(type)) {
const { ofType } = type;
if ((0, graphql_1.isScalarType)(ofType) || (0, graphql_1.isEnumType)(ofType)) {
return `Array<${(0, types_1.typeNameFromGraphQLType)(generator.context, ofType)}>`;
}
}
if ((0, graphql_1.isScalarType)(type) || (0, graphql_1.isEnumType)(type)) {
return (0, types_1.typeNameFromGraphQLType)(generator.context, type);
}
else {
let returnType = (0, codeGeneration_1.interfaceNameFromOperation)({ operationName, operationType });
if (op.operationType === 'subscription' && op.fields.length) {
returnType = `Pick<__SubscriptionContainer, "${op.fields[0].responseName}">`;
}
if ((0, graphql_2.isList)(type)) {
returnType = `Array<${returnType}>`;
}
return returnType;
}
}
function generateAngularService(generator, context, options) {
var _a;
const isAngularV6 = (_a = options === null || options === void 0 ? void 0 : options.isAngularV6) !== null && _a !== void 0 ? _a : false;
const operations = context.operations;
generator.printOnNewline(`@Injectable({
providedIn: 'root'
})`);
generator.printOnNewline(`export class APIService {`);
generator.withIndent(() => {
if (isAngularV6) {
generator.printOnNewline('public client: Client;');
generateServiceConstructor(generator);
}
Object.values(operations).forEach((op) => {
if (op.operationType === 'subscription') {
return generateSubscriptionOperation(generator, op, { isAngularV6 });
}
if (op.operationType === 'query' || op.operationType === 'mutation') {
return generateQueryOrMutationOperation(generator, op, { isAngularV6 });
}
});
generator.printOnNewline('}');
});
}
function generateServiceConstructor(generator) {
generator.printOnNewline();
generator.print(`constructor() {`);
generator.withIndent(() => {
generator.print(`this.client = generateClient();`);
});
generator.printOnNewline('}');
}
function generateSubscriptionOperation(generator, op, options) {
var _a;
const isAngularV6 = (_a = options === null || options === void 0 ? void 0 : options.isAngularV6) !== null && _a !== void 0 ? _a : false;
const statement = formatTemplateString(generator, op.source);
const { operationName } = op;
const vars = variablesFromField(generator.context, op.variables);
const returnType = getReturnTypeName(generator, op);
generator.printNewline();
const subscriptionName = `${operationName}Listener`;
if (!vars.length) {
if (isAngularV6) {
generator.print(`${subscriptionName}(): Observable<GraphQLResult<${returnType}>> { return this.client.graphql({ query: \n\`${statement}\` }) as any; }`);
}
else {
generator.print(`${subscriptionName}: Observable<SubscriptionResponse<${returnType}>> = API.graphql(graphqlOperation(\n\`${statement}\`)) as Observable<SubscriptionResponse<${returnType}>>`);
}
}
else {
generator.print(`${subscriptionName}(`);
variableDeclaration(generator, vars);
if (isAngularV6) {
generator.print(`) : Observable<GraphQLResult<${returnType}>> {`);
}
else {
generator.print(`) : Observable<SubscriptionResponse<${returnType}>> {`);
}
generator.withIndent(() => {
generator.printNewlineIfNeeded();
generator.print(`const statement = \`${statement}\``);
const params = ['statement'];
variableAssignmentToInput(generator, vars);
params.push('gqlAPIServiceArguments');
if (isAngularV6) {
generator.printOnNewline(`return this.client.graphql({ query: statement, variables: gqlAPIServiceArguments }) as any;`);
}
else {
generator.printOnNewline(`return API.graphql(graphqlOperation(${params.join(', ')})) as Observable<SubscriptionResponse<${returnType}>>;`);
}
generator.printOnNewline('}');
});
}
generator.printNewline();
}
function generateQueryOrMutationOperation(generator, op, options) {
var _a;
const isAngularV6 = (_a = options === null || options === void 0 ? void 0 : options.isAngularV6) !== null && _a !== void 0 ? _a : false;
const statement = formatTemplateString(generator, op.source);
const vars = variablesFromField(generator.context, op.variables);
const returnType = getReturnTypeName(generator, op);
const resultField = getOperationResultField(op);
const resultProp = resultField ? `.${resultField.responseName}` : '';
generator.printNewline();
generator.print(`async ${op.operationName}(`);
variableDeclaration(generator, vars);
generator.print(`) : Promise<${returnType}> {`);
generator.withIndent(() => {
generator.printNewlineIfNeeded();
generator.print(`const statement = \`${statement}\``);
const params = ['statement'];
if (op.variables.length) {
variableAssignmentToInput(generator, vars);
params.push('gqlAPIServiceArguments');
}
if (isAngularV6) {
generator.printOnNewline(`const response = await this.client.graphql({ query: statement, ${op.variables.length ? `variables: gqlAPIServiceArguments, ` : ''}}) as any;`);
}
else {
generator.printOnNewline(`const response = await API.graphql(graphqlOperation(${params.join(', ')})) as any;`);
}
generator.printOnNewline(`return (<${returnType}>response.data${resultProp})`);
});
generator.printOnNewline('}');
}
function variablesFromField(context, fields) {
return fields.map(field => propertyFromVar(context, field));
}
exports.variablesFromField = variablesFromField;
function propertyFromVar(context, field) {
let { name: fieldName, type: fieldType } = field;
fieldName = fieldName || field.responseName;
const propertyName = fieldName;
let property = { fieldName, fieldType, propertyName };
let isNullable = true;
if (fieldType instanceof graphql_1.GraphQLNonNull) {
isNullable = false;
}
const typeName = (0, types_1.typeNameFromGraphQLType)(context, fieldType, null, false);
return Object.assign(Object.assign({}, property), { typeName, isComposite: false, fieldType, isNullable });
}
exports.propertyFromVar = propertyFromVar;
function variableDeclaration(generator, properties) {
properties
.sort((a, b) => {
if (!a.isNullable && b.isNullable) {
return -1;
}
if (!b.isNullable && a.isNullable) {
return 1;
}
return 0;
})
.forEach(property => {
const { fieldName, typeName, isArray, isNullable } = property;
generator.print(fieldName);
if (isNullable) {
generator.print('?');
}
generator.print(':');
if (isArray) {
generator.print(' Array<');
}
generator.print(`${typeName}`);
if (isArray) {
generator.print('>');
}
generator.print(', ');
});
}
function variableAssignmentToInput(generator, vars) {
if (vars.length > 0) {
generator.printOnNewline('const gqlAPIServiceArguments : any = ');
generator.withinBlock(() => {
vars
.filter(v => !v.isNullable)
.forEach(v => {
generator.printOnNewline(`${v.fieldName},`);
});
}, '{', '}');
vars
.filter(v => v.isNullable)
.forEach(v => {
generator.printOnNewline(`if (${v.fieldName}) `);
generator.withinBlock(() => {
generator.printOnNewline(`gqlAPIServiceArguments.${v.fieldName} = ${v.fieldName}`);
}, '{', '}');
});
}
}
function formatTemplateString(generator, str) {
const indentation = ' '.repeat(generator.currentFile.indentWidth * (generator.currentFile.indentLevel + 2));
return str
.split('\n')
.map((line, idx) => (idx > 0 ? indentation + line : line))
.join('\n');
}
//# sourceMappingURL=index.js.map
;