Socket
Socket
Sign inDemoInstall

apollo-codegen

Package Overview
Dependencies
113
Maintainers
1
Versions
102
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.12.10 to 0.13.0

11

lib/cli.js

@@ -121,4 +121,9 @@ #!/usr/bin/env node

demand: false,
describe: "Automatically add the __typename field to every selection set",
default: true
describe: "For non-swift targets, always add the __typename GraphQL introspection type when generating target types",
default: false
},
"tag-name": {
demand: false,
describe: "Name of the template literal tag used to identify template literals containing GraphQL queries in Javascript/Typescript code",
default: 'gql'
}

@@ -139,3 +144,3 @@ }, argv => {

};
_1.generate(inputPaths, argv.schema, argv.output, argv.target, options);
_1.generate(inputPaths, argv.schema, argv.output, argv.target, argv.tagName, options);
})

@@ -142,0 +147,0 @@ .fail(function (message, error) {

@@ -5,3 +5,2 @@ "use strict";

const change_case_1 = require("change-case");
const Inflector = require("inflected");
const printing_1 = require("../utilities/printing");

@@ -11,3 +10,3 @@ const CodeGenerator_1 = require("../utilities/CodeGenerator");

const types_1 = require("./types");
function generateSource(context, options) {
function generateSource(context) {
const generator = new CodeGenerator_1.default(context);

@@ -17,8 +16,9 @@ generator.printOnNewline('/* @flow */');

typeDeclarationForGraphQLType(context.typesUsed.forEach(type => typeDeclarationForGraphQLType(generator, type)));
const fragmentsWithTypenameField = {};
Object.values(context.operations).forEach(operation => {
interfaceVariablesDeclarationForOperation(generator, operation);
typeDeclarationForOperation(generator, operation, fragmentsWithTypenameField);
typeDeclarationForOperation(generator, operation);
});
Object.values(context.fragments).forEach(operation => typeDeclarationForFragment(generator, operation, fragmentsWithTypenameField));
Object.values(context.fragments).forEach(fragment => {
typeDeclarationForFragment(generator, fragment);
});
return generator.output;

@@ -40,3 +40,8 @@ }

generator.printNewlineIfNeeded();
generator.printOnNewline(description && `// ${description}`);
if (description) {
description.split('\n')
.forEach(line => {
generator.printOnNewline(`// ${line.trim()}`);
});
}
generator.printOnNewline(`export type ${name} =`);

@@ -84,72 +89,69 @@ const nValues = values.length;

exports.interfaceVariablesDeclarationForOperation = interfaceVariablesDeclarationForOperation;
function typeDeclarationForOperation(generator, { operationName, operationType, variables, fields, fragmentSpreads, inlineFragments, fragmentsReferenced, source, }, fragmentsWithTypenameField) {
if (hasTypenameField(fields)) {
console.error('__typename on operations are not yet supported');
}
function typeDeclarationForOperation(generator, { operationName, operationType, variables, fields, fragmentSpreads, fragmentsReferenced, source, }) {
const interfaceName = interfaceNameFromOperation({ operationName, operationType });
const properties = propertiesFromFields(generator.context, fields, {
typeNameSuffix: `From${operationName}`
});
language_1.typeDeclaration(generator, { interfaceName }, () => {
const properties = propertiesFromFields(generator.context, fields);
language_1.typeDeclaration(generator, {
interfaceName,
}, () => {
propertyDeclarations(generator, properties, true);
});
properties.forEach(({ fragmentSpreads, inlineFragments, bareTypeName }) => {
if (fragmentSpreads && fragmentSpreads.length > 0) {
fragmentSpreads.forEach(fragmentSpread => {
fragmentsWithTypenameField[fragmentSpread] = true;
});
}
if (inlineFragments && inlineFragments.length > 0) {
const fragmentName = `${change_case_1.pascalCase(bareTypeName)}From${operationName}`;
handleInlineFragments(generator, fragmentName, inlineFragments);
}
});
}
exports.typeDeclarationForOperation = typeDeclarationForOperation;
function typeDeclarationForFragment(generator, { fragmentName, typeCondition, fields, inlineFragments, fragmentSpreads, source, possibleTypes }, fragmentsWithTypenameField) {
function typeDeclarationForFragment(generator, fragment) {
const { fragmentName, typeCondition, fields, inlineFragments, fragmentSpreads, source, } = fragment;
const interfaceName = `${change_case_1.pascalCase(fragmentName)}Fragment`;
if (inlineFragments.length > 0) {
handleInlineFragments(generator, interfaceName, inlineFragments);
}
else {
language_1.typeDeclaration(generator, {
interfaceName,
}, () => {
if (fragmentsWithTypenameField[fragmentName]) {
addTypenameFieldIfNeeded(generator, fields, typeCondition);
}
const properties = propertiesFromFields(generator.context, fields, {
typeNameSuffix: 'Fragment'
language_1.typeDeclaration(generator, {
interfaceName,
noBrackets: graphql_1.isAbstractType(typeCondition)
}, () => {
if (graphql_1.isAbstractType(typeCondition)) {
const propertySets = fragment.possibleTypes
.map(type => {
const inlineFragment = inlineFragments.find(inlineFragment => {
return inlineFragment.typeCondition.toString() == type;
});
if (inlineFragment) {
const fields = inlineFragment.fields.map(field => {
if (field.fieldName === '__typename') {
return Object.assign({}, field, { typeName: `"${inlineFragment.typeCondition}"`, type: { name: `"${inlineFragment.typeCondition}"` } });
}
else {
return field;
}
});
return propertiesFromFields(generator, fields);
}
else {
const fragmentFields = fields.map(field => {
if (field.fieldName === '__typename') {
return Object.assign({}, field, { typeName: `"${type}"`, type: { name: `"${type}"` } });
}
else {
return field;
}
});
return propertiesFromFields(generator, fragmentFields);
}
});
language_1.propertySetsDeclaration(generator, fragment, propertySets, true);
}
else {
const properties = propertiesFromFields(generator.context, fields);
propertyDeclarations(generator, properties, true);
});
}
}
});
}
exports.typeDeclarationForFragment = typeDeclarationForFragment;
function propertiesFromFields(context, fields, { forceNullable, typeNameSuffix } = {}) {
return fields.map(field => propertyFromField(context, field, { forceNullable, typeNameSuffix }));
function propertiesFromFields(context, fields, forceNullable) {
return fields.map(field => propertyFromField(context, field, forceNullable));
}
exports.propertiesFromFields = propertiesFromFields;
function propertyFromField(context, field, { forceNullable, typeNameSuffix } = {}) {
function propertyFromField(context, field, forceNullable) {
let { name: fieldName, type: fieldType, description, fragmentSpreads, inlineFragments } = field;
fieldName = fieldName || field.responseName;
const propertyName = fieldName;
let property = { fieldName, fieldType, propertyName, description, inlineFragments };
let property = { fieldName, fieldType, propertyName, description };
const namedType = graphql_1.getNamedType(fieldType);
if (graphql_1.isCompositeType(namedType)) {
let typeName, bareTypeName;
if (propertyName === '__typename') {
bareTypeName = `"${fieldType}"`;
typeName = `"${fieldType}"`;
}
else {
bareTypeName = change_case_1.pascalCase(Inflector.singularize(propertyName));
if (inlineFragments && inlineFragments.length > 0 ||
fragmentSpreads && fragmentSpreads.length > 0) {
typeName = types_1.typeNameFromGraphQLType(context, fieldType, `${change_case_1.pascalCase(bareTypeName)}${typeNameSuffix}`);
}
else {
typeName = types_1.typeNameFromGraphQLType(context, fieldType, bareTypeName);
}
}
const typeName = types_1.typeNameFromGraphQLType(context, fieldType);
let isArray = false;

@@ -166,8 +168,14 @@ if (fieldType instanceof graphql_1.GraphQLList) {

}
return Object.assign({}, property, { typeName, bareTypeName, fields: field.fields, isComposite: true, fragmentSpreads, inlineFragments, fieldType,
return Object.assign({}, property, { typeName, fields: field.fields, isComposite: true, fragmentSpreads, inlineFragments, fieldType,
isArray, isNullable });
}
else {
const typeName = types_1.typeNameFromGraphQLType(context, fieldType);
return Object.assign({}, property, { typeName, isComposite: false, fieldType });
if (field.fieldName === '__typename') {
const typeName = types_1.typeNameFromGraphQLType(context, fieldType, null, false);
return Object.assign({}, property, { typeName, isComposite: false, fieldType, isNullable: false });
}
else {
const typeName = types_1.typeNameFromGraphQLType(context, fieldType);
return Object.assign({}, property, { typeName, isComposite: false, fieldType });
}
}

@@ -180,9 +188,39 @@ }

properties.forEach(property => {
if (property.fields && property.fields.length > 0 ||
property.inlineFragments && property.inlineFragments.length > 0) {
if (property.inlineFragments.length > 0) {
language_1.propertyDeclaration(generator, Object.assign({}, property, { inInterface }));
}
else {
language_1.propertyDeclaration(generator, Object.assign({}, property, { inInterface }), () => {
if (graphql_1.isAbstractType(graphql_1.getNamedType(property.type || property.fieldType))) {
const possibleTypes = getPossibleTypes(generator, property);
const propertySets = Object.keys(possibleTypes)
.map(type => {
const inlineFragment = property.inlineFragments.find(inlineFragment => {
return inlineFragment.typeCondition.toString() == type;
});
if (inlineFragment) {
const fields = inlineFragment.fields.map(field => {
if (field.fieldName === '__typename') {
return Object.assign({}, field, { typeName: `"${inlineFragment.typeCondition}"`, type: { name: `"${inlineFragment.typeCondition}"` } });
}
else {
return field;
}
});
return propertiesFromFields(generator, fields);
}
else {
const fields = property.fields.map(field => {
if (field.fieldName === '__typename') {
return Object.assign({}, field, { typeName: `"${type}"`, type: { name: `"${type}"` } });
}
else {
return field;
}
});
return propertiesFromFields(generator, fields);
}
});
language_1.propertySetsDeclaration(generator, property, propertySets);
}
else {
if (property.fields && property.fields.length > 0
|| property.inlineFragments && property.inlineFragments.length > 0
|| property.fragmentSpreads && property.fragmentSpreads.length > 0) {
language_1.propertyDeclaration(generator, property, () => {
const properties = propertiesFromFields(generator.context, property.fields);

@@ -192,62 +230,12 @@ propertyDeclarations(generator, properties);

}
else {
language_1.propertyDeclaration(generator, Object.assign({}, property, { inInterface }));
}
}
else {
language_1.propertyDeclaration(generator, Object.assign({}, property, { inInterface }));
}
});
}
exports.propertyDeclarations = propertyDeclarations;
function makeTypenameField(typeName) {
return {
responseName: '__typename',
fieldName: '__typename',
type: typeName,
};
function getPossibleTypes(generator, property) {
return generator.context.schema._possibleTypeMap[graphql_1.getNamedType(property.fieldType || property.type)];
}
function hasTypenameField(fields) {
if (!fields) {
return false;
}
return fields.find(field => field.fieldName === '__typename' || field.responseName === '__typename');
}
function removeTypenameFieldIfExists(generator, fields) {
if (hasTypenameField(fields)) {
fields = fields.filter(field => field.fieldName !== '__typename' || field.responseName !== '__typename');
return true;
}
else {
return false;
}
}
function addTypenameFieldIfNeeded(generator, fields, parentTypeName) {
const removed = removeTypenameFieldIfExists();
if (generator.context.addTypename || removed) {
fields.unshift(makeTypenameField(parentTypeName));
}
}
function handleInlineFragments(generator, fragmentName, inlineFragments) {
let unionTypes = [];
inlineFragments.forEach(({ fields, typeCondition }) => {
const typeName = `${fragmentName}On${typeCondition}`;
unionTypes.push(typeName);
addTypenameFieldIfNeeded(generator, fields, typeCondition);
let properties = propertiesFromFields(generator.context, fields, {
typeNameSuffix: 'Fragment'
});
language_1.typeDeclaration(generator, {
interfaceName: typeName,
}, () => {
propertyDeclarations(generator, properties, true);
});
properties.forEach(({ inlineFragments, bareTypeName }) => {
if (inlineFragments && inlineFragments.length > 0) {
const innerFragmentName = `${bareTypeName}Fragment`;
handleInlineFragments(generator, innerFragmentName, inlineFragments);
}
});
});
language_1.typeDeclaration(generator, { interfaceName: fragmentName, noBrackets: true }, () => {
language_1.unionDeclaration(generator, unionTypes);
});
}
//# sourceMappingURL=codeGeneration.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const change_case_1 = require("change-case");
const codeGeneration_1 = require("./codeGeneration");
const types_1 = require("./types");
function typeDeclaration(generator, { interfaceName, noBrackets }, closure) {
generator.printNewlineIfNeeded();
generator.printNewline();
generator.print(`export type ${interfaceName} =`);
generator.print(`export type ${interfaceName} = `);
generator.pushScope({ typeName: interfaceName });
if (!noBrackets) {
generator.withinBlock(closure, ' {|', '|}');
if (noBrackets) {
generator.withinBlock(closure, '', '');
}
else {
generator.withinBlock(closure, '', '');
generator.withinBlock(closure, '{|', '|}');
}

@@ -19,6 +20,12 @@ generator.popScope();

exports.typeDeclaration = typeDeclaration;
function propertyDeclaration(generator, { propertyName, typeName, description, isArray, isNullable, inInterface, fragmentSpreads }, closure) {
generator.printOnNewline(description && `// ${description}`);
function propertyDeclaration(generator, { fieldName, type, propertyName, typeName, description, isArray, isNullable, inInterface, fragmentSpreads }, closure, open = ' {|', close = '|}') {
const name = fieldName || propertyName;
if (description) {
description.split('\n')
.forEach(line => {
generator.printOnNewline(`// ${line.trim()}`);
});
}
if (closure) {
generator.printOnNewline(`${propertyName}:`);
generator.printOnNewline(`${name}:`);
if (isNullable) {

@@ -31,11 +38,6 @@ generator.print(' ?');

}
generator.print('Array<');
generator.print(' Array<');
}
generator.pushScope({ typeName: propertyName });
generator.withinBlock(() => {
if (fragmentSpreads && fragmentSpreads.length > 0) {
fragmentSpreads.forEach(n => generator.printOnNewline(`...${change_case_1.pascalCase(n)}Fragment,`));
}
closure();
}, ' {|', '|}');
generator.pushScope({ typeName: name });
generator.withinBlock(closure, open, close);
generator.popScope();

@@ -46,14 +48,4 @@ if (isArray) {

}
else if (fragmentSpreads && fragmentSpreads.length === 1) {
generator.printOnNewline(`${propertyName}: ${isArray ? 'Array<' : ''}${change_case_1.pascalCase(fragmentSpreads[0])}Fragment${isArray ? '>' : ''}`);
}
else if (fragmentSpreads && fragmentSpreads.length > 1) {
generator.printOnNewline(`${propertyName}: ${isArray ? 'Array<' : ''}`);
generator.withinBlock(() => {
fragmentSpreads.forEach(n => generator.printOnNewline(`...${change_case_1.pascalCase(n)}Fragment,`));
}, '{|', '|}');
generator.print(isArray ? '>' : '');
}
else {
generator.printOnNewline(`${propertyName}: ${typeName}`);
generator.printOnNewline(`${name}: ${typeName || types_1.typeNameFromGraphQLType(generator.context, type)}`);
}

@@ -63,16 +55,40 @@ generator.print(',');

exports.propertyDeclaration = propertyDeclaration;
function propertyDeclarations(generator, properties) {
if (!properties)
return;
properties.forEach(property => propertyDeclaration(generator, property));
function propertySetsDeclaration(generator, property, propertySets, standalone = false) {
const { description, fieldName, propertyName, typeName, isNullable, isArray } = property;
const name = fieldName || propertyName;
if (description) {
description.split('\n')
.forEach(line => {
generator.printOnNewline(`// ${line.trim()}`);
});
}
if (!standalone) {
generator.printOnNewline(`${name}:`);
}
if (isNullable) {
generator.print(' ?');
}
if (isArray) {
generator.print('Array< ');
}
generator.pushScope({ typeName: name });
generator.withinBlock(() => {
propertySets.forEach((propertySet, index, propertySets) => {
generator.withinBlock(() => {
codeGeneration_1.propertyDeclarations(generator, propertySet);
});
if (index !== propertySets.length - 1) {
generator.print(' |');
}
});
}, '(', ')');
generator.popScope();
if (isArray) {
generator.print(' >');
}
if (!standalone) {
generator.print(',');
}
}
exports.propertyDeclarations = propertyDeclarations;
function unionDeclaration(generator, typeNames) {
if (!typeNames)
throw new Error('Union Declaration requires types');
typeNames.forEach(typeName => {
generator.printOnNewline(`| ${typeName}`);
});
}
exports.unionDeclaration = unionDeclaration;
exports.propertySetsDeclaration = propertySetsDeclaration;
//# sourceMappingURL=language.js.map

@@ -11,16 +11,10 @@ "use strict";

const flow_1 = require("./flow");
function generate(inputPaths, schemaPath, outputPath, target, options) {
function generate(inputPaths, schemaPath, outputPath, target, tagName, options) {
const schema = loading_1.loadSchema(schemaPath);
const document = loading_1.loadAndMergeQueryDocuments(inputPaths);
const document = loading_1.loadAndMergeQueryDocuments(inputPaths, tagName);
validation_1.validateQueryDocument(schema, document, target);
if (target === 'swift') {
if (!options.addTypename) {
console.warn('Apollo iOS requires the __typename field to be added automatically');
}
options.addTypename = true;
options.mergeInFieldsFromFragmentSpreads = true;
}
else {
options.mergeInFieldsFromFragmentSpreads = false;
}
options.mergeInFieldsFromFragmentSpreads = true;
const context = compilation_1.compileToIR(schema, document, options);

@@ -35,6 +29,6 @@ Object.assign(context, options);

case 'typescript':
output = typescript_1.generateSource(context, options);
output = typescript_1.generateSource(context);
break;
case 'flow':
output = flow_1.generateSource(context, options);
output = flow_1.generateSource(context);
break;

@@ -41,0 +35,0 @@ case 'swift':

@@ -17,4 +17,4 @@ "use strict";

exports.loadSchema = loadSchema;
function extractDocumentFromJavascript(content) {
const re = /gql`([^`]*)`/g;
function extractDocumentFromJavascript(content, tagName = 'gql') {
const re = new RegExp(tagName + '`([^`]*)`', 'g');
let match;

@@ -30,3 +30,3 @@ const matches = [];

}
function loadAndMergeQueryDocuments(inputPaths) {
function loadAndMergeQueryDocuments(inputPaths, tagName) {
const sources = inputPaths.map(inputPath => {

@@ -39,3 +39,3 @@ const body = fs.readFileSync(inputPath, 'utf8');

|| inputPath.endsWith('.tsx') || inputPath.endsWith('.ts')) {
const doc = extractDocumentFromJavascript(body.toString());
const doc = extractDocumentFromJavascript(body.toString(), tagName);
return doc ? new graphql_1.Source(doc, inputPath) : null;

@@ -42,0 +42,0 @@ }

@@ -5,3 +5,2 @@ "use strict";

const change_case_1 = require("change-case");
const Inflector = require("inflected");
const printing_1 = require("../utilities/printing");

@@ -11,3 +10,3 @@ const CodeGenerator_1 = require("../utilities/CodeGenerator");

const types_1 = require("./types");
function generateSource(context, options) {
function generateSource(context) {
const generator = new CodeGenerator_1.default(context);

@@ -17,8 +16,7 @@ generator.printOnNewline('/* tslint:disable */');

typeDeclarationForGraphQLType(context.typesUsed.forEach(type => typeDeclarationForGraphQLType(generator, type)));
const fragmentsWithTypenameField = {};
Object.values(context.operations).forEach(operation => {
interfaceVariablesDeclarationForOperation(generator, operation);
interfaceDeclarationForOperation(generator, operation, fragmentsWithTypenameField);
interfaceDeclarationForOperation(generator, operation);
});
Object.values(context.fragments).forEach(operation => interfaceDeclarationForFragment(generator, operation, fragmentsWithTypenameField));
Object.values(context.fragments).forEach(operation => interfaceDeclarationForFragment(generator, operation));
generator.printOnNewline('/* tslint:enable */');

@@ -42,3 +40,8 @@ generator.printNewline();

generator.printNewlineIfNeeded();
generator.printOnNewline(description && `// ${description}`);
if (description) {
description.split('\n')
.forEach(line => {
generator.printOnNewline(`// ${line.trim()}`);
});
}
generator.printOnNewline(`export type ${name} =`);

@@ -86,75 +89,69 @@ const nValues = values.length;

exports.interfaceVariablesDeclarationForOperation = interfaceVariablesDeclarationForOperation;
function interfaceDeclarationForOperation(generator, { operationName, operationType, variables, fields, fragmentSpreads, fragmentsReferenced, source, }, fragmentsWithTypenameField) {
if (hasTypenameField(fields)) {
console.error('__typename on operations are not yet supported');
}
function interfaceDeclarationForOperation(generator, { operationName, operationType, variables, fields, fragmentSpreads, fragmentsReferenced, source, }) {
const interfaceName = interfaceNameFromOperation({ operationName, operationType });
const properties = propertiesFromFields(generator.context, fields, {
typeNameSuffix: `From${operationName}`
});
const properties = propertiesFromFields(generator.context, fields);
language_1.interfaceDeclaration(generator, {
interfaceName,
extendTypes: fragmentSpreads ? fragmentSpreads.map(f => `${change_case_1.pascalCase(f)}Fragment`) : null,
}, () => {
propertyDeclarations(generator, properties, true);
});
properties.forEach(({ fragmentSpreads, inlineFragments, bareTypeName }) => {
if (fragmentSpreads && fragmentSpreads.length > 0) {
fragmentSpreads.forEach(fragmentSpread => {
fragmentsWithTypenameField[fragmentSpread] = true;
});
}
if (inlineFragments && inlineFragments.length > 0) {
const objectName = `${change_case_1.pascalCase(bareTypeName)}From${operationName}`;
handleInlineFragments(generator, objectName, inlineFragments);
}
});
}
exports.interfaceDeclarationForOperation = interfaceDeclarationForOperation;
function interfaceDeclarationForFragment(generator, { fragmentName, typeCondition, fields, inlineFragments, fragmentSpreads, source, possibleTypes }, fragmentsWithTypenameField) {
function interfaceDeclarationForFragment(generator, fragment) {
const { fragmentName, typeCondition, fields, inlineFragments, fragmentSpreads, source, } = fragment;
const interfaceName = `${change_case_1.pascalCase(fragmentName)}Fragment`;
if (inlineFragments.length > 0) {
handleInlineFragments(generator, interfaceName, inlineFragments);
}
else {
language_1.interfaceDeclaration(generator, {
interfaceName,
extendTypes: fragmentSpreads ? fragmentSpreads.map(f => `${change_case_1.pascalCase(f)}Fragment`) : null,
}, () => {
if (fragmentsWithTypenameField[fragmentName]) {
addTypenameFieldIfNeeded(generator, fields, typeCondition);
}
const properties = propertiesFromFields(generator.context, fields, {
typeNameSuffix: 'Fragment'
language_1.interfaceDeclaration(generator, {
interfaceName,
noBrackets: graphql_1.isAbstractType(typeCondition)
}, () => {
if (graphql_1.isAbstractType(typeCondition)) {
const propertySets = fragment.possibleTypes
.map(type => {
const inlineFragment = inlineFragments.find(inlineFragment => {
return inlineFragment.typeCondition.toString() == type;
});
if (inlineFragment) {
const fields = inlineFragment.fields.map(field => {
if (field.fieldName === '__typename') {
return Object.assign({}, field, { typeName: `"${inlineFragment.typeCondition}"`, type: { name: `"${inlineFragment.typeCondition}"` } });
}
else {
return field;
}
});
return propertiesFromFields(generator, fields);
}
else {
const fragmentFields = fields.map(field => {
if (field.fieldName === '__typename') {
return Object.assign({}, field, { typeName: `"${type}"`, type: { name: `"${type}"` } });
}
else {
return field;
}
});
return propertiesFromFields(generator, fragmentFields);
}
});
language_1.propertySetsDeclaration(generator, fragment, propertySets, true);
}
else {
const properties = propertiesFromFields(generator.context, fields);
propertyDeclarations(generator, properties, true);
});
}
}
});
}
exports.interfaceDeclarationForFragment = interfaceDeclarationForFragment;
function propertiesFromFields(context, fields, { forceNullable, typeNameSuffix } = {}) {
return fields.map(field => propertyFromField(context, field, { forceNullable, typeNameSuffix }));
function propertiesFromFields(context, fields, forceNullable) {
return fields.map(field => propertyFromField(context, field, forceNullable));
}
exports.propertiesFromFields = propertiesFromFields;
function propertyFromField(context, field, { forceNullable, typeNameSuffix } = {}) {
function propertyFromField(context, field, forceNullable) {
let { name: fieldName, type: fieldType, description, fragmentSpreads, inlineFragments } = field;
fieldName = fieldName || field.responseName;
const propertyName = fieldName;
let property = { fieldName, fieldType, propertyName, description, inlineFragments };
let property = { fieldName, fieldType, propertyName, description };
const namedType = graphql_1.getNamedType(fieldType);
if (graphql_1.isCompositeType(namedType)) {
let typeName, bareTypeName;
if (propertyName === '__typename') {
bareTypeName = `"${fieldType}"`;
typeName = `"${fieldType}"`;
}
else {
bareTypeName = change_case_1.pascalCase(Inflector.singularize(propertyName));
if (property.inlineFragments && property.inlineFragments.length > 0) {
typeName = types_1.typeNameFromGraphQLType(context, fieldType, `${change_case_1.pascalCase(bareTypeName)}${typeNameSuffix}`);
}
else {
typeName = types_1.typeNameFromGraphQLType(context, fieldType, bareTypeName);
}
}
const typeName = types_1.typeNameFromGraphQLType(context, fieldType);
let isArray = false;

@@ -171,8 +168,14 @@ if (fieldType instanceof graphql_1.GraphQLList) {

}
return Object.assign({}, property, { typeName, bareTypeName, fields: field.fields, isComposite: true, fragmentSpreads, inlineFragments, fieldType,
return Object.assign({}, property, { typeName, fields: field.fields, isComposite: true, fragmentSpreads, inlineFragments, fieldType,
isArray, isNullable });
}
else {
const typeName = types_1.typeNameFromGraphQLType(context, fieldType);
return Object.assign({}, property, { typeName, isComposite: false, fieldType });
if (field.fieldName === '__typename') {
const typeName = types_1.typeNameFromGraphQLType(context, fieldType, null, false);
return Object.assign({}, property, { typeName, isComposite: false, fieldType, isNullable: false });
}
else {
const typeName = types_1.typeNameFromGraphQLType(context, fieldType);
return Object.assign({}, property, { typeName, isComposite: false, fieldType });
}
}

@@ -185,8 +188,39 @@ }

properties.forEach(property => {
if (property.fields && property.fields.length > 0 || property.inlineFragments && property.inlineFragments.length > 0) {
if (property.inlineFragments.length > 0) {
language_1.propertyDeclaration(generator, Object.assign({}, property, { inInterface }));
}
else {
language_1.propertyDeclaration(generator, Object.assign({}, property, { inInterface }), () => {
if (graphql_1.isAbstractType(graphql_1.getNamedType(property.type || property.fieldType))) {
const possibleTypes = getPossibleTypes(generator, property);
const propertySets = Object.keys(possibleTypes)
.map(type => {
const inlineFragment = property.inlineFragments.find(inlineFragment => {
return inlineFragment.typeCondition.toString() == type;
});
if (inlineFragment) {
const fields = inlineFragment.fields.map(field => {
if (field.fieldName === '__typename') {
return Object.assign({}, field, { typeName: `"${inlineFragment.typeCondition}"`, type: { name: `"${inlineFragment.typeCondition}"` } });
}
else {
return field;
}
});
return propertiesFromFields(generator, fields);
}
else {
const fields = property.fields.map(field => {
if (field.fieldName === '__typename') {
return Object.assign({}, field, { typeName: `"${type}"`, type: { name: `"${type}"` } });
}
else {
return field;
}
});
return propertiesFromFields(generator, fields);
}
});
language_1.propertySetsDeclaration(generator, property, propertySets);
}
else {
if (property.fields && property.fields.length > 0
|| property.inlineFragments && property.inlineFragments.length > 0
|| property.fragmentSpreads && property.fragmentSpreads.length > 0) {
language_1.propertyDeclaration(generator, property, () => {
const properties = propertiesFromFields(generator.context, property.fields);

@@ -196,70 +230,12 @@ propertyDeclarations(generator, properties);

}
else {
language_1.propertyDeclaration(generator, Object.assign({}, property, { inInterface }));
}
}
else {
language_1.propertyDeclaration(generator, Object.assign({}, property, { inInterface }));
}
});
}
exports.propertyDeclarations = propertyDeclarations;
function makeTypenameField(typeName) {
return {
responseName: '__typename',
fieldName: '__typename',
type: typeName,
};
function getPossibleTypes(generator, property) {
return generator.context.schema._possibleTypeMap[graphql_1.getNamedType(property.fieldType || property.type)];
}
function hasTypenameField(fields) {
if (!fields) {
return false;
}
return fields.find(field => field.fieldName === '__typename' || field.responseName === '__typename');
}
function removeTypenameFieldIfExists(generator, fields) {
if (hasTypenameField(fields)) {
fields = fields.filter(field => field.fieldName !== '__typename' || field.responseName !== '__typename');
return true;
}
else {
return false;
}
}
function addTypenameFieldIfNeeded(generator, fields, parentTypeName) {
const removed = removeTypenameFieldIfExists();
if (generator.context.addTypename || removed) {
fields.unshift(makeTypenameField(parentTypeName));
}
}
function handleInlineFragments(generator, fragmentName, inlineFragments) {
let typeNames = [];
inlineFragments.forEach(inlineFragment => {
const typeName = `${fragmentName}On${inlineFragment.typeCondition}`;
typeNames.push(typeName);
const hasTypenameField = inlineFragment.fields
.find(field => field.fieldName === '__typename' || field.responseName === '__typename');
let fields = inlineFragment.fields;
if (hasTypenameField) {
fields = fields.filter(field => field.fieldName !== '__typename' || field.responseName !== '__typename');
}
if (generator.context.addTypename || hasTypenameField) {
fields.unshift(makeTypenameField(inlineFragment.typeCondition));
}
let properties = propertiesFromFields(generator.context, fields, {
typeNameSuffix: 'Fragment'
});
language_1.interfaceDeclaration(generator, {
interfaceName: typeName,
}, () => {
propertyDeclarations(generator, properties, true);
});
properties.forEach(property => {
if (property.inlineFragments && property.inlineFragments.length > 0) {
const innerFragmentName = `${change_case_1.pascalCase(property.bareTypeName)}Fragment`;
handleInlineFragments(generator, innerFragmentName, property.inlineFragments);
}
});
});
language_1.typeDeclaration(generator, { interfaceName: fragmentName, noBrackets: true }, () => {
language_1.unionDeclaration(generator, typeNames);
});
}
//# sourceMappingURL=codeGeneration.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const change_case_1 = require("change-case");
function interfaceDeclaration(generator, { interfaceName, extendTypes }, closure) {
const codeGeneration_1 = require("./codeGeneration");
const types_1 = require("./types");
function interfaceDeclaration(generator, { interfaceName, noBrackets }, closure) {
generator.printNewlineIfNeeded();
generator.printNewline();
generator.print(`export interface ${interfaceName}`);
if (extendTypes && extendTypes.length > 0) {
generator.print(` extends ${extendTypes.join(', ')}`);
}
generator.print(`export type ${interfaceName} = `);
generator.pushScope({ typeName: interfaceName });
generator.withinBlock(closure);
generator.popScope();
}
exports.interfaceDeclaration = interfaceDeclaration;
function typeDeclaration(generator, { interfaceName, noBrackets }, closure) {
generator.printNewlineIfNeeded();
generator.printNewline();
generator.print(`export type ${interfaceName} =`);
generator.pushScope({ typeName: interfaceName });
if (!noBrackets) {
generator.withinBlock(closure);
if (noBrackets) {
generator.withinBlock(closure, '', '');
}
else {
generator.withinBlock(closure, '', '');
generator.withinBlock(closure, '{', '}');
}
generator.popScope();
generator.print(';');
}
exports.typeDeclaration = typeDeclaration;
function propertyDeclaration(generator, { propertyName, typeName, description, isArray, isNullable, inInterface, fragmentSpreads }, closure) {
generator.printOnNewline(description && `// ${description}`);
exports.interfaceDeclaration = interfaceDeclaration;
function propertyDeclaration(generator, { fieldName, type, propertyName, typeName, description, isArray, isNullable, inInterface, fragmentSpreads }, closure) {
const name = fieldName || propertyName;
if (description) {
description.split('\n')
.forEach(line => {
generator.printOnNewline(`// ${line.trim()}`);
});
}
if (closure) {
generator.printOnNewline(`${propertyName}:`);
generator.printOnNewline(`${name}: `);
if (isArray) {
generator.print(' Array<');
}
if (fragmentSpreads && fragmentSpreads.length > 0) {
generator.print(` ${fragmentSpreads.map(n => `${change_case_1.pascalCase(n)}Fragment`).join(' & ')} &`);
}
generator.pushScope({ typeName: propertyName });
generator.pushScope({ typeName: name });
generator.withinBlock(closure);

@@ -50,25 +43,46 @@ generator.popScope();

}
else if (fragmentSpreads && fragmentSpreads.length > 0) {
generator.printOnNewline(`${propertyName}: ${isArray ? 'Array<' : ''}${fragmentSpreads.map(n => `${change_case_1.pascalCase(n)}Fragment`).join(' & ')}${isArray ? '>' : ''}`);
}
else {
generator.printOnNewline(`${propertyName}: ${typeName}`);
generator.printOnNewline(`${name}: ${typeName || types_1.typeNameFromGraphQLType(generator.context, type)}`);
}
generator.print(inInterface ? ';' : ',');
generator.print(',');
}
exports.propertyDeclaration = propertyDeclaration;
function propertyDeclarations(generator, properties) {
if (!properties)
return;
properties.forEach(property => propertyDeclaration(generator, property));
function propertySetsDeclaration(generator, property, propertySets, standalone = false) {
const { description, fieldName, propertyName, typeName, isNullable, isArray } = property;
const name = fieldName || propertyName;
if (description) {
description.split('\n')
.forEach(line => {
generator.printOnNewline(`// ${line.trim()}`);
});
}
if (!standalone) {
generator.printOnNewline(`${name}: `);
}
if (isArray) {
generator.print(' Array<');
}
generator.pushScope({ typeName: name });
generator.withinBlock(() => {
propertySets.forEach((propertySet, index, propertySets) => {
generator.withinBlock(() => {
codeGeneration_1.propertyDeclarations(generator, propertySet);
});
if (index !== propertySets.length - 1) {
generator.print(' |');
}
});
}, '(', ')');
generator.popScope();
if (isArray) {
generator.print(' >');
}
if (isNullable) {
generator.print(' | null');
}
if (!standalone) {
generator.print(',');
}
}
exports.propertyDeclarations = propertyDeclarations;
function unionDeclaration(generator, typeNames) {
if (!typeNames)
throw new Error('Union Declaration requires types');
typeNames.forEach(typeName => {
generator.printOnNewline(`| ${typeName}`);
});
}
exports.unionDeclaration = unionDeclaration;
exports.propertySetsDeclaration = propertySetsDeclaration;
//# sourceMappingURL=language.js.map

@@ -74,3 +74,3 @@ "use strict";

if (!mutationType) {
throw new GraphQLError('Schema is not configured for mutations', [operation]);
throw new graphql_1.GraphQLError('Schema is not configured for mutations', [operation]);
}

@@ -81,7 +81,7 @@ return mutationType;

if (!subscriptionType) {
throw new GraphQLError('Schema is not configured for subscriptions', [operation]);
throw new graphql_1.GraphQLError('Schema is not configured for subscriptions', [operation]);
}
return subscriptionType;
default:
throw new GraphQLError('Can only compile queries, mutations and subscriptions', [operation]);
throw new graphql_1.GraphQLError('Can only compile queries, mutations and subscriptions', [operation]);
}

@@ -88,0 +88,0 @@ }

{
"name": "apollo-codegen",
"version": "0.12.10",
"version": "0.13.0",
"description": "Generate API code or type annotations based on a GraphQL schema and query documents",

@@ -30,3 +30,3 @@ "main": "./lib/index.js",

"@types/yargs": "^6.6.0",
"ansi-regex": "^2.1.1",
"ansi-regex": "^3.0.0",
"common-tags": "^1.3.0",

@@ -42,6 +42,5 @@ "jest": "^20.0.4",

"graphql": "^0.10.0",
"inflected": "^1.1.7",
"inflected": "^2.0.2",
"mkdirp": "^0.5.1",
"node-fetch": "^1.5.3",
"source-map-support": "^0.4.2",
"yargs": "^8.0.1"

@@ -48,0 +47,0 @@ },

@@ -60,2 +60,86 @@ # Apollo GraphQL code generator

The tag name is configurable using the CLI `--tag-name` option.
## Typescript and Flow
When using `apollo-codegen` with Typescript or Flow, make sure to add the `__typename` introspection field to every selection set within your graphql operations.
If you're using a client like `apollo-client` that does this automatically for your GraphQL operations, pass in the -`-addTypename` option to `apollo-codegen` to make sure the generated Typescript and Flow types have the `__typename` field as well. This is required to ensure proper type generation support for `GraphQLUnionType` and `GraphQLInterfaceType` fields.
### Why is the __typename field required?
Using the type information from the GraphQL schema, we can infer the possible types for fields. However, in the case of a `GraphQLUnionType` or `GraphQLInterfaceType`, there are multiple types that are possible for that field. This is best modeled using a disjoint union with the `__typename`
as the discriminant.
For example, given a schema:
```graphql
...
interface Character {
name: String!
}
type Human implements Character {
homePlanet: String
}
type Droid implements Character {
primaryFunction: String
}
...
```
Whenever a field of type `Character` is encountered, it could be either a Human or Droid. Human and Droid objects
will have a different set of fields. Within your application code, when interacting with a `Character` you'll want to make sure to handle both of these cases.
Given this query:
```graphql
query Characters {
characters(episode: NEW_HOPE) {
name
... on Human {
homePlanet
}
... on Droid {
primaryFunction
}
}
}
```
Apollo Codegen will generate a union type for Character.
```javascript
export type CharactersQuery = {
characters: Array<{
__typename: 'Human',
name: string,
homePlanet: ?string
} | {
__typename: 'Droid',
name: string,
primaryFunction: ?string
}>
}
```
This type can then be used as follows to ensure that all possible types are handled:
```javascript
function CharacterFigures({ characters }: CharactersQuery) {
return characters.map(character => {
switch(character.__typename) {
case "Human":
return <HumanFigure homePlanet={character.homePlanet} name={character.name} />
case "Droid":
return <DroidFigure primaryFunction={character.homePlanet} name={character.name} />
}
});
}
```
## Contributing

@@ -62,0 +146,0 @@

@@ -33,6 +33,5 @@ import {

const compileFromSource = (source, addTypename = false) => {
const compileFromSource = (source) => {
const document = parse(source);
const context = compileToIR(schema, document, { mergeInFieldsFromFragmentSpreads: false } );
context.addTypename = addTypename;
const context = compileToIR(schema, document, { mergeInFieldsFromFragmentSpreads: true, addTypename: true } );
generator.context = context;

@@ -51,107 +50,2 @@ return context;

describe('#generateSource()', function() {
describe('__typename', function() {
test('in an object', function() {
const { compileFromSource } = setup(swapiSchema);
const context = compileFromSource(`
query HeroName {
hero {
__typename
name
}
}
`);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
// TODO: Enable after fixing operation
test.skip('in an operation', function() {
const { compileFromSource } = setup(swapiSchema);
const context = compileFromSource(`
query Hero {
...Hero
}
fragment Hero on Query {
hero {
__typename
name
}
}
`);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
test('single fragment spread', () => {
const { compileFromSource } = setup(swapiSchema);
const context = compileFromSource(`
query HeroName {
hero {
...humanFriends
}
}
fragment humanFriends on Character {
friends {
__typename
name
}
}
`);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
test('in fragment spreads, allows for disjoint union via __typename string literals', function() {
const { compileFromSource } = setup(swapiSchema);
const context = compileFromSource(`
query HeroName {
hero {
__typename
...humanHero
...droidHero
}
}
fragment droidHero on Droid {
primaryFunction
}
fragment humanHero on Human {
homePlanet
}
`);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
test('in inline fragments, allows for disjoint union via __typename string literals', function() {
const { compileFromSource } = setup(swapiSchema);
const context = compileFromSource(`
query HeroName {
hero {
__typename
... on Droid {
friends {
name
}
}
... on Human {
homePlanet
}
}
}
`);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
});
test(`should generate simple query operations`, function() {

@@ -223,28 +117,2 @@ const { compileFromSource } = setup(swapiSchema);

test(`should handle multi-fragmented query operations`, function() {
const { compileFromSource } = setup(swapiSchema);
const context = compileFromSource(`
query HeroAndFriendsNames {
hero {
name
...heroFriends
...heroAppears
}
}
fragment heroFriends on Character {
friends {
name
}
}
fragment heroAppears on Character {
appearsIn
}
`);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
test(`should generate query operations with inline fragments`, function() {

@@ -336,39 +204,2 @@ const { compileFromSource } = setup(swapiSchema);

test(`should handle complex fragments with type aliases`, function() {
const { compileFromSource } = setup(swapiSchema);
const context = compileFromSource(`
query HeroAndFriendsNames {
hero(episode: NEWHOPE) {
name
...Something
}
empireHero: hero(episode: EMPIRE) {
name
...Something
}
}
fragment Something on Character {
... on Human {
friends {
... on Human {
homePlanet
}
... on Droid {
primaryFunction
}
}
}
... on Droid {
appearsIn
}
}
`);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
test(`should annotate custom scalars as string`, function() {

@@ -388,20 +219,11 @@ const { compileFromSource } = setup(miscSchema);

test('should correctly handle fragments on interfaces', function() {
const {compileFromSource} = setup(swapiSchema);
const context = compileFromSource(
`
query HeroQuery($episode: Episode){
hero(episode: $episode) {
name
... on Human {
homePlanet
}
... on Droid {
primaryFunction
}
test('should handle single line comments', () => {
const { compileFromSource } = setup(miscSchema);
const context = compileFromSource(`
query CustomScalar {
commentTest {
singleLine
}
}
`
);
`);

@@ -412,143 +234,16 @@ const source = generateSource(context);

test('should correctly handle fragment spreads on interfaces', function() {
const {compileFromSource} = setup(swapiSchema);
const context = compileFromSource(
`
query HeroQuery($episode: Episode){
hero(episode: $episode) {
name
...humanFragment
...droidFragment
test('should handle multi-line comments', () => {
const { compileFromSource } = setup(miscSchema);
const context = compileFromSource(`
query CustomScalar {
commentTest {
multiLine
}
}
`);
fragment humanFragment on Human {
homePlanet
}
fragment droidFragment on Droid {
primaryFunction
}
`
);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
test('should correctly handle nested fragments on interfaces', function() {
const {compileFromSource} = setup(swapiSchema);
const context = compileFromSource(
`
query HeroQuery($episode: Episode){
hero(episode: $episode) {
name
friendsConnection {
friends {
...CharacterFragment
}
}
}
}
fragment CharacterFragment on Character {
name
... on Human {
homePlanet
}
... on Droid {
primaryFunction
}
}
`
);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
test('should correctly add typename to nested fragments on interfaces if addTypename is true', function() {
const {compileFromSource} = setup(swapiSchema);
const context = compileFromSource(
`
query HeroQuery($episode: Episode){
hero(episode: $episode) {
name
friendsConnection {
friends {
...CharacterFragment
}
}
}
}
fragment CharacterFragment on Character {
name
... on Human {
homePlanet
}
... on Droid {
primaryFunction
}
}
`
);
const source = generateSource(context, { addTypename: true });
expect(source).toMatchSnapshot();
});
test('should correctly handle doubly nested fragments on interfaces', function() {
const {compileFromSource} = setup(swapiSchema);
const context = compileFromSource(
`
query HeroQuery($episode: Episode) {
hero(episode: $episode) {
name
friendsConnection {
friends {
...CharacterFragment
}
}
}
}
fragment CharacterFragment on Character {
name
... on Human {
homePlanet
friends {
...OtherCharacterFragment
}
}
... on Droid {
primaryFunction
}
}
fragment OtherCharacterFragment on Character {
... on Human {
height
}
... on Droid {
appearsIn
}
}
`
);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
});
});

@@ -26,2 +26,14 @@ {

"deprecationReason": null
},
{
"name": "commentTest",
"description": "",
"args": [],
"type": {
"kind": "OBJECT",
"name": "CommentTest",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}

@@ -126,2 +138,37 @@ ],

"kind": "OBJECT",
"name": "CommentTest",
"description": "This is a type to test comments",
"fields": [
{
"name": "singleLine",
"description": "This is a single-line comment",
"args": [],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "multiLine",
"description": "This is a multi-line\ncomment.",
"args": [],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "__Schema",

@@ -128,0 +175,0 @@ "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.",

@@ -18,3 +18,4 @@ import { stripIndent } from 'common-tags';

import { loadSchema } from '../../src/loading';
const schema = loadSchema(require.resolve('../starwars/schema.json'));
const swapiSchema = loadSchema(require.resolve('../starwars/schema.json'));
const miscSchema = loadSchema(require.resolve('../misc/schema.json'));

@@ -30,3 +31,3 @@ import CodeGenerator from '../../src/utilities/CodeGenerator';

beforeEach(function() {
function setup(schema) {
const context = {

@@ -36,3 +37,3 @@ schema: schema,

fragments: {},
typesUsed: {},
typesUsed: {}
}

@@ -42,6 +43,8 @@

compileFromSource = (source, addTypename = false) => {
compileFromSource = (source) => {
const document = parse(source);
const context = compileToIR(schema, document, { mergeInFieldsFromFragmentSpreads: false });
context.addTypename = addTypename;
const context = compileToIR(schema, document, {
mergeInFieldsFromFragmentSpreads: true,
addTypename: true
});
generator.context = context;

@@ -54,106 +57,9 @@ return context;

};
});
return { generator, compileFromSource, addFragment };
}
describe('#generateSource()', function() {
describe('__typename', function() {
test('in an object', function() {
const context = compileFromSource(`
query HeroName {
hero {
__typename
name
}
}
`);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
// TODO: Enable after fixing operation
test.skip('in an operation', function() {
const context = compileFromSource(`
query Hero {
...Hero
}
fragment Hero on Query {
hero {
__typename
name
}
}
`);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
test('single fragment spread', () => {
const context = compileFromSource(`
query HeroName {
hero {
...humanFriends
}
}
fragment humanFriends on Character {
friends {
__typename
name
}
}
`);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
test('in fragment spreads, allows for disjoint union via __typename string literals', function() {
const context = compileFromSource(`
query HeroName {
hero {
__typename
...humanHero
...droidHero
}
}
fragment droidHero on Droid {
primaryFunction
}
fragment humanHero on Human {
homePlanet
}
`);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
test('in inline fragments, allows for disjoint union via __typename string literals', function() {
const context = compileFromSource(`
query HeroName {
hero {
__typename
... on Droid {
friends {
name
}
}
... on Human {
homePlanet
}
}
}
`);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
});
test(`should generate simple query operations`, function() {
const { compileFromSource } = setup(swapiSchema);
const context = compileFromSource(`

@@ -172,2 +78,3 @@ query HeroName {

test(`should generate simple query operations including input variables`, function() {
const { compileFromSource } = setup(swapiSchema);
const context = compileFromSource(`

@@ -186,2 +93,3 @@ query HeroName($episode: Episode) {

test(`should generate simple nested query operations including input variables`, function() {
const { compileFromSource } = setup(swapiSchema);
const context = compileFromSource(`

@@ -203,2 +111,3 @@ query HeroAndFriendsNames($episode: Episode) {

test(`should generate fragmented query operations`, function() {
const { compileFromSource } = setup(swapiSchema);
const context = compileFromSource(`

@@ -223,28 +132,4 @@ query HeroAndFriendsNames {

test(`should handle multi-fragmented query operations`, function() {
const context = compileFromSource(`
query HeroAndFriendsNames {
hero {
name
...heroFriends
...heroAppears
}
}
fragment heroFriends on Character {
friends {
name
}
}
fragment heroAppears on Character {
appearsIn
}
`);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
test(`should generate query operations with inline fragments`, function() {
const { compileFromSource } = setup(swapiSchema);
const context = compileFromSource(`

@@ -273,2 +158,3 @@ query HeroAndDetails {

test(`should generate mutation operations with complex input types`, function() {
const { compileFromSource } = setup(swapiSchema);
const context = compileFromSource(`

@@ -287,3 +173,4 @@ mutation ReviewMovie($episode: Episode, $review: ReviewInput) {

test(`should generate correct typedefs with a single custom fragment`, function() {
test(`should generate correct list with custom fragment`, function() {
const { compileFromSource } = setup(swapiSchema);
const context = compileFromSource(`

@@ -308,19 +195,8 @@ fragment Friend on Character {

test(`should generate correct typedefs with a multiple custom fragments`, function() {
test('should handle single line comments', () => {
const { compileFromSource } = setup(miscSchema);
const context = compileFromSource(`
fragment Friend on Character {
name
}
fragment Person on Character {
name
}
query HeroAndFriendsNames($episode: Episode) {
hero(episode: $episode) {
name
friends {
...Friend
...Person
}
query CustomScalar {
commentTest {
singleLine
}

@@ -334,32 +210,10 @@ }

test(`should handle complex fragments with type aliases`, function() {
test('should handle multi-line comments', () => {
const { compileFromSource } = setup(miscSchema);
const context = compileFromSource(`
query HeroAndFriendsNames {
hero(episode: NEWHOPE) {
name
...Something
query CustomScalar {
commentTest {
multiLine
}
empireHero: hero(episode: EMPIRE) {
name
...Something
}
}
fragment Something on Character {
... on Human {
friends {
... on Human {
homePlanet
}
... on Droid {
primaryFunction
}
}
}
... on Droid {
appearsIn
}
}
`);

@@ -370,139 +224,3 @@

});
test('should correctly handle fragments on interfaces', function() {
const context = compileFromSource(
`
query HeroQuery($episode: Episode){
hero(episode: $episode) {
name
... on Human {
homePlanet
}
... on Droid {
primaryFunction
}
}
}
`
);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
test('should correctly handle nested fragments on interfaces', function() {
const context = compileFromSource(
`
query HeroQuery($episode: Episode){
hero(episode: $episode) {
name
friendsConnection {
friends {
...CharacterFragment
}
}
}
}
fragment CharacterFragment on Character {
name
__typename
... on Human {
homePlanet
}
... on Droid {
primaryFunction
}
}
`
);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
test('should correctly add typename to nested fragments on interfaces if addTypename is true', function() {
const context = compileFromSource(
`
query HeroQuery($episode: Episode){
hero(episode: $episode) {
name
friendsConnection {
friends {
...CharacterFragment
}
}
}
}
fragment CharacterFragment on Character {
name
__typename
... on Human {
homePlanet
}
... on Droid {
primaryFunction
}
}
`
);
const source = generateSource(context, { addTypename: true });
expect(source).toMatchSnapshot();
});
test('should correctly handle doubly nested fragments on interfaces', function() {
const context = compileFromSource(
`
query HeroQuery($episode: Episode) {
hero(episode: $episode) {
name
friendsConnection {
friends {
...CharacterFragment
}
}
}
}
fragment CharacterFragment on Character {
name
... on Human {
homePlanet
friends {
...OtherCharacterFragment
}
}
... on Droid {
primaryFunction
}
}
fragment OtherCharacterFragment on Character {
... on Human {
height
}
... on Droid {
appearsIn
}
}
`
);
const source = generateSource(context);
expect(source).toMatchSnapshot();
});
});
});

@@ -24,3 +24,3 @@ import { readFileSync } from 'fs';

test(`should throw an error for ExplicitTypename.graphql when the target is Swift`, () => {
test(`should throw an error for ExplicitTypename.graphql for the Swift target`, () => {
const inputPaths = [

@@ -38,14 +38,2 @@ path.join(__dirname, './starwars/ExplicitTypename.graphql'),

test(`should not throw an error for ExplicitTypename.graphql when the target is not Swift`, () => {
const inputPaths = [
path.join(__dirname, './starwars/ExplicitTypename.graphql'),
];
const document = loadAndMergeQueryDocuments(inputPaths);
validateQueryDocument(schema, document, 'flow');
validateQueryDocument(schema, document, 'typescript');
validateQueryDocument(schema, document, 'ts');
validateQueryDocument(schema, document, 'json');
});
test(`should throw an error for TypenameAlias.graphql`, () => {

@@ -52,0 +40,0 @@ const inputPaths = [

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc