All files / domains/arg compiler.ts

88.71% Statements 55/62
90% Branches 36/40
90% Functions 9/10
89.83% Lines 53/59

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 13417x               17x 17x 17x 17x 17x 17x 17x 17x   34x 34x 32x 32x 3x   29x   34x 32x   34x     34x 32x 32x 2x   30x 1x   29x 1x     30x     19x 19x 18x   19x     30x 30x 30x 30x 9x   21x 21x 28x 28x   28x 9x   19x 19x         21x     62x 62x   62x 28x   34x 34x     30x   17x                                                                                          
import {
  GraphQLFieldConfigArgumentMap,
  GraphQLType,
  GraphQLInputType,
  isInputType,
  GraphQLNonNull,
} from 'graphql';
import { resolveType } from 'services/utils';
import { injectorRegistry } from 'domains/inject';
import { ArgsIndex, argRegistry } from './registry';
import { ArgError } from './error';
import { defaultArgOptions } from './options';
import { getParameterNames } from 'services/utils';
 
function compileInferedAndRegisterdArgs(infered: any[], registeredArgs: ArgsIndex = {}) {
  const argsMerged = infered.map((inferedType, index) => {
    const registered = registeredArgs[index];
    if (registered && registered.type) {
      return registered.type;
    }
    return inferedType;
  });
 
  const resolvedArgs = argsMerged.map((rawType, index) => {
    return resolveType(rawType);
  });
 
  return resolvedArgs;
}
 
function validateArgs(
  target: Function,
  fieldName: string,
  types: GraphQLType[],
): types is GraphQLInputType[] {
  types.forEach((argType, argIndex) => {
    const isInjectedArg = injectorRegistry.has(target, fieldName, argIndex);
 
    if (!isInjectedArg && !argType) {
      throw new ArgError(
        target,
        fieldName,
        argIndex,
        `Could not infer type of argument. Make sure to use native GraphQLInputType, native scalar like 'String' or class decorated with @InputObjectType`,
      );
    }
 
    if (!isInjectedArg && !isInputType(argType)) {
      throw new ArgError(
        target,
        fieldName,
        argIndex,
        `Argument has incorrect type. Make sure to use native GraphQLInputType, native scalar like 'String' or class decorated with @InputObjectType`,
      );
    }
 
    if (isInjectedArg && argRegistry.has(target, fieldName, argIndex)) {
      throw new ArgError(
        target,
        fieldName,
        argIndex,
        `Argument cannot be marked wiht both @Arg and @Inject or custom injector`,
      );
    }
  });
  return true;
}
 
function enhanceType(originalType: GraphQLInputType, isNullable: boolean) {
  let finalType = originalType;
  if (!isNullable) {
    finalType = new GraphQLNonNull(finalType);
  }
  return finalType;
}
 
function convertArgsArrayToArgsMap(
  target: Function,
  fieldName: string,
  argsTypes: GraphQLInputType[],
  registeredArgs: ArgsIndex = {},
): GraphQLFieldConfigArgumentMap {
  const functionDefinition = target.prototype[fieldName];
  coInst argNames = getParameterNames(functionDefinition);

  if (!argNames || !argNames.length) {
    return {};
  }
 
  const argsMap: GraphQLFieldConfigArgumentMap = {};
  argNames.forEach((argName, index) => {
    const argConfig = registeredArgs[index] || { ...defaultArgOptions };
    const argType = argsTypes[index];
 
    // don't publish args marked as auto Injected
    if (injectorRegistry.has(target, fieldName, index)) {
      return;
    }
 
    let finalType = enhanceType(argType, argConfig.isNullable);
 
    argsMap[argName] = {
      type: finalType,
      description: argConfig.description,
    };
  });
  return argsMap;
}
 
export function compileFieldArgs(
  target: Function,
  fieldName: string,
): GraphQLFieldConfigArgumentMap {
  const registeredArgs = argRegistry.getAll(target)[fieldName];
  const inferedRawArgs = Reflect.getMetadata(
    'design:paramtypes',
    target.prototype,
    fieldName,
  );
 
  // There are no arguments
  if (!inferedRawArgs) {
    return {};
  }
 
  const argTypes = compileInferedAndRegisterdArgs(inferedRawArgs, registeredArgs);
 
  if (!validateArgs(target, fieldName, argTypes)) {
    return;
  }
 
  return convertArgsArrayToArgsMap(target, fieldName, argTypes, registeredArgs);
}