All files / src parser.ts

100% Statements 34/34
87.5% Branches 28/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              1x   1x 1x 1x 1x                 1x     1x 20x 20x                 16x               15x 17x     15x 17x     15x 17x     15x 17x     15x           15x                 13x 13x   13x   13x               13x 13x   13x 6x   7x     13x 13x 13x    
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: 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;
}