All files / src parser.ts

100% Statements 34/34
96.88% Branches 31/32
100% Functions 6/6
100% Lines 32/32
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              28x   28x 28x 28x 28x                 28x     28x 662x 662x                 97x               96x 99x     96x 99x     96x 99x     96x 99x     96x           95x                 93x 93x   93x   93x               93x 93x   93x 79x   14x     93x 93x 93x    
import {
  DocumentNode,
  DefinitionNode,
  VariableDefinitionNode,
  OperationDefinitionNode,
} from 'graphql';
 
const invariant = require('invariant');
 
export enum DocumentType {
  Query,
  Mutation,
  Subscription,
}
 
export interface IDocumentDefinition {
  type: DocumentType;
  name: string;
  variables: ReadonlyArray<VariableDefinitionNode>;
}
 
const cache = new Map();
 
// the parser is mainly a safety check for the HOC
export function parser(document: DocumentNode): IDocumentDefinition {
  const cached = cache.get(document);
  if (cached) return cached;
  // variables
  let variables, type, name;
 
  /*
 
    Saftey checks for proper usage of react-apollo
 
  */
  invariant(
    !!document && !!document.kind,
    // tslint:disable-line
    `Argument of ${document} passed to parser was not a valid GraphQL ` +
      `DocumentNode. You may need to use 'graphql-tag' or another method ` +
      `to convert your operation into a document`,
  );
 
  const fragments = document.definitions.filter(
    (x: DefinitionNode) => x.kind === 'FragmentDefinition',
  );
 
  const queries = document.definitions.filter(
    (x: DefinitionNode) => x.kind === 'OperationDefinition' && x.operation === 'query',
  );
 
  const mutations = document.definitions.filter(
    (x: DefinitionNode) => x.kind === 'OperationDefinition' && x.operation === 'mutation',
  );
 
  const subscriptions = document.definitions.filter(
    (x: DefinitionNode) => x.kind === 'OperationDefinition' && x.operation === 'subscription',
  );
 
  invariant(
    !fragments.length || (queries.length || mutations.length || subscriptions.length),
    `Passing only a fragment to 'graphql' is not yet supported. ` +
      `You must include a query, subscription or mutation as well`,
  );
 
  invariant(
    queries.length + mutations.length + subscriptions.length <= 1,
    // tslint:disable-line
    `react-apollo only supports a query, subscription, or a mutation per HOC. ` +
      `${document} had ${queries.length} queries, ${subscriptions.length} ` +
      `subscriptions and ${mutations.length} mutations. ` +
      `You can use 'compose' to join multiple operation types to a component`,
  );
 
  type = queries.length ? DocumentType.Query : DocumentType.Mutation;
  if (!queries.length && !mutations.length) type = DocumentType.Subscription;
 
  const definitions = queries.length ? queries : mutations.length ? mutations : subscriptions;
 
  invariant(
    definitions.length === 1,
    // tslint:disable-line
    `react-apollo only supports one defintion per HOC. ${document} had ` +
      `${definitions.length} definitions. ` +
      `You can use 'compose' to join multiple operation types to a component`,
  );
 
  const definition = definitions[0] as OperationDefinitionNode;
  variables = definition.variableDefinitions || [];
 
  if (definition.name && definition.name.kind === 'Name') {
    name = definition.name.value;
  } else {
    name = 'data'; // fallback to using data if no name
  }
 
  const payload = { name, type, variables };
  cache.set(document, payload);
  return payload;
}