graphql#GraphQLInputType TypeScript Examples

The following examples show how to use graphql#GraphQLInputType. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utils.ts    From tql with MIT License 7 votes vote down vote up
export function inputType(type: GraphQLInputType): GraphQLInputType {
  if (type instanceof GraphQLNonNull) {
    return inputType(type.ofType);
  } else if (type instanceof GraphQLList) {
    return inputType(type.ofType);
  } else {
    return type;
  }
}
Example #2
Source File: utils.ts    From tql with MIT License 7 votes vote down vote up
export function listType(type: GraphQLOutputType | GraphQLInputType): boolean {
  if (type instanceof GraphQLNonNull) {
    return listType(type.ofType);
  } else if (type instanceof GraphQLList) {
    return true;
  } else {
    return false;
  }
}
Example #3
Source File: schema-resolver.ts    From graphql-mesh with MIT License 6 votes vote down vote up
resolve(input: { type: SoapType; isList: boolean }): GraphQLInputType {
    try {
      const type: GraphQLInputType = this.resolveInputType(input.type);
      return input.isList ? new GraphQLList(type) : type;
    } catch (err) {
      const errStacked = new Error(`could not resolve output type for ${util.inspect(input)}`);
      errStacked.stack += '\nCaused by: ' + err.stack;
      throw errStacked;
    }
  }
Example #4
Source File: schema-resolver.ts    From graphql-mesh with MIT License 6 votes vote down vote up
private resolveInputType(soapType: SoapType): GraphQLInputType {
    if (this.alreadyResolved.has(soapType)) {
      return this.alreadyResolved.get(soapType);
    }

    if (typeof soapType === 'string') {
      const customType: GraphQLInputType = this.options.customResolver.inputType(soapType);
      if (customType) {
        this.alreadyResolved.set(soapType, customType);
        return customType;
      }
    } else if (soapType?.name && soapType?.fields?.length > 0) {
      const objectType: GraphQLInputObjectType = this.createObjectType(soapType);
      if (objectType) {
        this.alreadyResolved.set(soapType, objectType);
        return objectType;
      }
    }

    this.logger.warn(`could not resolve input type '${soapType}'; using GraphQLString`);
    this.alreadyResolved.set(soapType, GraphQLString);
    return GraphQLString;
  }
Example #5
Source File: resolveDataByUnionInputType.ts    From graphql-mesh with MIT License 6 votes vote down vote up
export function resolveDataByUnionInputType(data: any, type: GraphQLInputType, schemaComposer: SchemaComposer): any {
  if (data) {
    if (isListType(type)) {
      return asArray(data).map(elem => resolveDataByUnionInputType(elem, type.ofType, schemaComposer));
    }
    if (isNonNullType(type)) {
      return resolveDataByUnionInputType(data, type.ofType, schemaComposer);
    }
    if (isInputObjectType(type)) {
      const fieldMap = type.getFields();
      const isOneOf = schemaComposer.getAnyTC(type).getDirectiveByName('oneOf');
      data = asArray(data)[0];
      for (const propertyName in data) {
        const fieldName = sanitizeNameForGraphQL(propertyName);
        const field = fieldMap[fieldName];
        if (field) {
          if (isOneOf) {
            const resolvedData = resolveDataByUnionInputType(data[fieldName], field.type, schemaComposer);
            return resolvedData;
          }
          const realFieldName = (field.extensions?.propertyName as string) || fieldName;
          data[realFieldName] = resolveDataByUnionInputType(data[fieldName], field.type, schemaComposer);
        }
      }
    }
  }
  return data;
}
Example #6
Source File: resolver-data-factory.ts    From graphql-mesh with MIT License 6 votes vote down vote up
export function parseInterpolationStrings(
  interpolationStrings: string[],
  argTypeMap?: Record<string, string | GraphQLInputType>
) {
  const interpolationKeys = getInterpolationKeys(...interpolationStrings);

  const args: Record<string, { type: string | GraphQLInputType }> = {};
  const contextVariables: string[] = [];

  for (const interpolationKey of interpolationKeys) {
    const interpolationKeyParts = interpolationKey.split('.');
    const varName = interpolationKeyParts[interpolationKeyParts.length - 1];
    if (interpolationKeyParts[0] === 'args') {
      const argType = argTypeMap && varName in argTypeMap ? argTypeMap[varName] : 'ID';
      args[varName] = {
        type: argType,
      };
    } else if (interpolationKeyParts[0] === 'context') {
      contextVariables.push(varName);
    }
  }

  return {
    args,
    contextVariables,
  };
}
Example #7
Source File: printers.ts    From tql with MIT License 6 votes vote down vote up
printInputType = (type: GraphQLInputType): string => {
  const isList = listType(type);
  const base = inputType(type);

  return (
    (() => {
      if (base instanceof GraphQLScalarType) {
        return toPrimitive(base);
      } else if (base instanceof GraphQLEnumType) {
        return base.name;
      } else if (base instanceof GraphQLInputObjectType) {
        return "I" + base.name;
      } else {
        throw new Error("Unable to render inputType.");
      }
    })() + (isList ? "[]" : "")
  );
}
Example #8
Source File: custom-type-resolver.ts    From graphql-mesh with MIT License 5 votes vote down vote up
inputType(typeName: string): GraphQLInputType {
    return this.resolve(typeName);
  }
Example #9
Source File: schema-resolver.ts    From graphql-mesh with MIT License 5 votes vote down vote up
private alreadyResolved: Map<SoapType, GraphQLInputType> = new Map();
Example #10
Source File: renderTyping.ts    From genql with MIT License 5 votes vote down vote up
render = (
  type: GraphQLOutputType | GraphQLInputType,
  nonNull: boolean,
  root: boolean,
  undefinableValues: boolean,
  undefinableFields: boolean,
  wrap: (x: string) => string = x => x
): string => {
    
  if (root) {
    if (undefinableFields) {
      if (isNonNullType(type)) {
        return `: ${render(type.ofType, true, false, undefinableValues, undefinableFields, wrap)}`
      } else {
        const rendered = render(type, true, false, undefinableValues, undefinableFields, wrap)
        return undefinableValues ? `?: ${rendered}` : `?: (${rendered} | null)`
      }
    } else {
      return `: ${render(type, false, false, undefinableValues, undefinableFields, wrap)}`
    }
  }

  if (isNamedType(type)) {
    let typeName = type.name

    // if is a scalar use the scalar interface to not expose reserved words
    if (isScalarType(type)) {
      typeName = `Scalars['${typeName}']`
    }

    const typing = wrap(typeName)

    if (undefinableValues) {
      return nonNull ? typing : `(${typing} | undefined)`
    } else {
      return nonNull ? typing : `(${typing} | null)`
    }
  }

  if (isListType(type)) {
    const typing = `${render(type.ofType, false, false, undefinableValues, undefinableFields, wrap)}[]`

    if (undefinableValues) {
      return nonNull ? typing : `(${typing} | undefined)`
    } else {
      return nonNull ? typing : `(${typing} | null)`
    }
  }

  return render((<GraphQLNonNull<any>>type).ofType, true, false, undefinableValues, undefinableFields, wrap)
}
Example #11
Source File: renderTyping.ts    From genql with MIT License 5 votes vote down vote up
renderTyping = (
  type: GraphQLOutputType | GraphQLInputType,
  undefinableValues: boolean,
  undefinableFields: boolean,
  root = true,
  wrap: any = undefined
) => render(type, false, root, undefinableValues, undefinableFields, wrap)
Example #12
Source File: index.ts    From graphql-mesh with MIT License 4 votes vote down vote up
async getMeshSource(): Promise<MeshSource> {
    const {
      addLimitArgument,
      baseUrl,
      customFetch,
      genericPayloadArgName,
      operationHeaders,
      qs,
      selectQueryOrMutationField,
    } = this.config;

    let fetch: WindowOrWorkerGlobalScope['fetch'];
    if (customFetch) {
      fetch = await loadFromModuleExportExpression(customFetch, {
        defaultExportName: 'default',
        cwd: this.baseDir,
        importFn: this.importFn,
      });
    } else {
      fetch = getCachedFetch(this.cache);
    }

    const spec = await this.getCachedSpec(fetch);

    const headersFactory = getInterpolatedHeadersFactory(operationHeaders);
    const queryStringFactoryMap = new Map<string, ResolverDataBasedFactory<string>>();
    for (const queryName in qs || {}) {
      queryStringFactoryMap.set(queryName, getInterpolatedStringFactory(qs[queryName]));
    }
    const searchParamsFactory = (resolverData: ResolverData, searchParams: URLSearchParams) => {
      for (const queryName in qs || {}) {
        searchParams.set(queryName, queryStringFactoryMap.get(queryName)(resolverData));
      }
      return searchParams;
    };

    const { schema } = await createGraphQLSchema(spec, {
      fetch,
      baseUrl,
      operationIdFieldNames: this.config.operationIdFieldNames,
      fillEmptyResponses: true,
      includeHttpDetails: this.config.includeHttpDetails,
      provideErrorExtensions: this.config.provideErrorExtensions,
      genericPayloadArgName: genericPayloadArgName === undefined ? false : genericPayloadArgName,
      selectQueryOrMutationField:
        selectQueryOrMutationField === undefined
          ? {}
          : selectQueryOrMutationField.reduce((acc, curr) => {
              let operationType: GraphQLOperationType;
              switch (curr.type) {
                case 'Query':
                  operationType = GraphQLOperationType.Query;
                  break;
                case 'Mutation':
                  operationType = GraphQLOperationType.Mutation;
                  break;
              }
              return {
                ...acc,
                [curr.title]: {
                  ...acc[curr.title],
                  [curr.path]: {
                    ...((acc[curr.title] && acc[curr.title][curr.path]) || {}),
                    [curr.method]: operationType,
                  },
                },
              };
            }, {} as OasTitlePathMethodObject<GraphQLOperationType>),
      addLimitArgument: addLimitArgument === undefined ? true : addLimitArgument,
      sendOAuthTokenInQuery: true,
      viewer: false,
      equivalentToMessages: true,
      pubsub: this.pubsub,
      logger: this.logger,
      resolverMiddleware: (getResolverParams, originalFactory) => (root, args, context, info: any) => {
        const resolverData: ResolverData = { root, args, context, info, env: process.env };
        const resolverParams = getResolverParams();
        resolverParams.requestOptions = {
          headers: headersFactory(resolverData),
        };
        resolverParams.qs = qs;

        /* FIXME: baseUrl is coming from Fastify Request
        if (context?.baseUrl) {
          resolverParams.baseUrl = context.baseUrl;
        }
        */

        if (baseUrl) {
          resolverParams.baseUrl = stringInterpolator.parse(baseUrl, resolverData);
        }

        if (resolverParams.baseUrl) {
          const urlObj = new URL(resolverParams.baseUrl);
          searchParamsFactory(resolverData, urlObj.searchParams);
        } else {
          this.logger.debug(
            () =>
              `Warning: There is no 'baseUrl' defined for this OpenAPI definition. We recommend you to define one manually!`
          );
        }

        if (context?.fetch) {
          resolverParams.fetch = context.fetch;
        }

        if (context?.qs) {
          resolverParams.qs = context.qs;
        }

        return originalFactory(() => resolverParams, this.logger)(root, args, context, info);
      },
    });

    const { args, contextVariables } = parseInterpolationStrings(Object.values(operationHeaders || {}));

    const rootFields = [
      ...Object.values(schema.getQueryType()?.getFields() || {}),
      ...Object.values(schema.getMutationType()?.getFields() || {}),
      ...Object.values(schema.getSubscriptionType()?.getFields() || {}),
    ];

    await Promise.all(
      rootFields.map(rootField =>
        Promise.all(
          Object.entries(args).map(async ([argName, { type }]) =>
            (rootField?.args as GraphQLArgument[]).push({
              name: argName,
              description: undefined,
              defaultValue: undefined,
              extensions: undefined,
              astNode: undefined,
              deprecationReason: undefined,
              type: (typeof type === 'string' ? (schema.getType(type) as GraphQLInputType) : type) || GraphQLID,
            })
          )
        )
      )
    );

    contextVariables.push('fetch' /*, 'baseUrl' */);

    return {
      schema,
      contextVariables,
    };
  }
Example #13
Source File: index.ts    From graphql-mesh with MIT License 4 votes vote down vote up
async getMeshSource() {
    const { schemaHeaders, serviceName, operationHeaders } = this.config;

    const thriftAST = await this.idl.getWithSet(async () => {
      const rawThrift = await readFileOrUrl<string>(this.config.idl, {
        allowUnknownExtensions: true,
        cwd: this.baseDir,
        headers: schemaHeaders,
      });
      const parseResult = parse(rawThrift, { organize: false });
      if (parseResult.type === SyntaxType.ThriftErrors) {
        throw new AggregateError(parseResult.errors);
      }
      return parseResult;
    });

    const enumTypeMap = new Map<string, GraphQLEnumType>();
    const outputTypeMap = new Map<string, GraphQLOutputType>();
    const inputTypeMap = new Map<string, GraphQLInputType>();
    const rootFields: GraphQLFieldConfigMap<any, any> = {};
    const annotations: IThriftAnnotations = {};
    const methodAnnotations: IMethodAnnotations = {};
    const methodNames: string[] = [];
    const methodParameters: {
      [methodName: string]: number;
    } = {};

    type TypeVal = BaseTypeVal | ListTypeVal | SetTypeVal | MapTypeVal | EnumTypeVal | StructTypeVal | VoidTypeVal;
    type BaseTypeVal = {
      id?: number;
      type: TType.BOOL | TType.BYTE | TType.DOUBLE | TType.I16 | TType.I32 | TType.I64 | TType.STRING;
    };
    type ListTypeVal = { id?: number; type: TType.LIST; elementType: TypeVal };
    type SetTypeVal = { id?: number; type: TType.SET; elementType: TypeVal };
    type MapTypeVal = { id?: number; type: TType.MAP; keyType: TypeVal; valType: TypeVal };
    type EnumTypeVal = { id?: number; type: TType.ENUM };
    type StructTypeVal = { id?: number; type: TType.STRUCT; name: string; fields: TypeMap };
    type VoidTypeVal = { id?: number; type: TType.VOID };
    type TypeMap = Record<string, TypeVal>;
    const topTypeMap: TypeMap = {};

    class MeshThriftClient<Context = any> extends ThriftClient<Context> {
      public static readonly serviceName: string = serviceName;
      public static readonly annotations: IThriftAnnotations = annotations;
      public static readonly methodAnnotations: IMethodAnnotations = methodAnnotations;
      public static readonly methodNames: Array<string> = methodNames;
      public readonly _serviceName: string = serviceName;
      public readonly _annotations: IThriftAnnotations = annotations;
      public readonly _methodAnnotations: IMethodAnnotations = methodAnnotations;
      public readonly _methodNames: Array<string> = methodNames;
      public readonly _methodParameters?: {
        [methodName: string]: number;
      } = methodParameters;

      writeType(typeVal: TypeVal, value: any, output: TProtocol) {
        switch (typeVal.type) {
          case TType.BOOL:
            output.writeBool(value);
            break;
          case TType.BYTE:
            output.writeByte(value);
            break;
          case TType.DOUBLE:
            output.writeDouble(value);
            break;
          case TType.I16:
            output.writeI16(value);
            break;
          case TType.I32:
            output.writeI32(value);
            break;
          case TType.I64:
            output.writeI64(value.toString());
            break;
          case TType.STRING:
            output.writeString(value);
            break;
          case TType.STRUCT: {
            output.writeStructBegin(typeVal.name);
            const typeMap = typeVal.fields;
            for (const argName in value) {
              const argType = typeMap[argName];
              const argVal = value[argName];
              if (argType) {
                output.writeFieldBegin(argName, argType.type, argType.id);
                this.writeType(argType, argVal, output);
                output.writeFieldEnd();
              }
            }
            output.writeFieldStop();
            output.writeStructEnd();
            break;
          }
          case TType.ENUM:
            // TODO: A
            break;
          case TType.MAP: {
            const keys = Object.keys(value);
            output.writeMapBegin(typeVal.keyType.type, typeVal.valType.type, keys.length);
            for (const key of keys) {
              this.writeType(typeVal.keyType, key, output);
              const val = value[key];
              this.writeType(typeVal.valType, val, output);
            }
            output.writeMapEnd();
            break;
          }
          case TType.LIST:
            output.writeListBegin(typeVal.elementType.type, value.length);
            for (const element of value) {
              this.writeType(typeVal.elementType, element, output);
            }
            output.writeListEnd();
            break;
          case TType.SET:
            output.writeSetBegin(typeVal.elementType.type, value.length);
            for (const element of value) {
              this.writeType(typeVal.elementType, element, output);
            }
            output.writeSetEnd();
            break;
        }
      }

      readType(type: TType, input: TProtocol): any {
        switch (type) {
          case TType.BOOL:
            return input.readBool();
          case TType.BYTE:
            return input.readByte();
          case TType.DOUBLE:
            return input.readDouble();
          case TType.I16:
            return input.readI16();
          case TType.I32:
            return input.readI32();
          case TType.I64:
            return BigInt(input.readI64().toString());
          case TType.STRING:
            return input.readString();
          case TType.STRUCT: {
            const result: any = {};
            input.readStructBegin();
            while (true) {
              const field: IThriftField = input.readFieldBegin();
              const fieldType = field.fieldType;
              const fieldName = field.fieldName || 'success';
              if (fieldType === TType.STOP) {
                break;
              }
              result[fieldName] = this.readType(fieldType, input);
              input.readFieldEnd();
            }
            input.readStructEnd();
            return result;
          }
          case TType.ENUM:
            // TODO: A
            break;
          case TType.MAP: {
            const result: any = {};
            const map = input.readMapBegin();
            for (let i = 0; i < map.size; i++) {
              const key = this.readType(map.keyType, input);
              const value = this.readType(map.valueType, input);
              result[key] = value;
            }
            input.readMapEnd();
            return result;
          }
          case TType.LIST: {
            const result: any[] = [];
            const list = input.readListBegin();
            for (let i = 0; i < list.size; i++) {
              const element = this.readType(list.elementType, input);
              result.push(element);
            }
            input.readListEnd();
            return result;
          }
          case TType.SET: {
            const result: any[] = [];
            const list = input.readSetBegin();
            for (let i = 0; i < list.size; i++) {
              const element = this.readType(list.elementType, input);
              result.push(element);
            }
            input.readSetEnd();
            return result;
          }
        }
      }

      async doRequest(methodName: string, args: any, fields: TypeMap, context?: any) {
        const Transport = this.transport;
        const Protocol = this.protocol;
        const writer: TTransport = new Transport();
        const output: TProtocol = new Protocol(writer);
        const id = this.incrementRequestId();
        output.writeMessageBegin(methodName, MessageType.CALL, id);
        this.writeType(
          {
            name: pascalCase(methodName) + '__Args',
            type: TType.STRUCT,
            fields,
            id,
          },
          args,
          output
        );
        output.writeMessageEnd();
        const data: Buffer = await this.connection.send(writer.flush(), context);
        const reader: TTransport = this.transport.receiver(data);
        const input: TProtocol = new Protocol(reader);
        const { fieldName, messageType }: IThriftMessage = input.readMessageBegin();
        if (fieldName === methodName) {
          if (messageType === MessageType.EXCEPTION) {
            const err: TApplicationException = TApplicationExceptionCodec.decode(input);
            input.readMessageEnd();
            return Promise.reject(err);
          } else {
            const result = this.readType(TType.STRUCT, input);
            input.readMessageEnd();
            if (result.success != null) {
              return result.success;
            } else {
              throw new TApplicationException(
                TApplicationExceptionType.UNKNOWN,
                methodName + ' failed: unknown result'
              );
            }
          }
        } else {
          throw new TApplicationException(
            TApplicationExceptionType.WRONG_METHOD_NAME,
            'Received a response to an unknown RPC function: ' + fieldName
          );
        }
      }
    }
    const thriftHttpClient = createHttpClient(MeshThriftClient, {
      ...this.config,
      requestOptions: {
        headers: operationHeaders,
      },
    });

    function processComments(comments: Comment[]) {
      return comments.map(comment => comment.value).join('\n');
    }

    function getGraphQLFunctionType(
      functionType: FunctionType,
      id = Math.random()
    ): { outputType: GraphQLOutputType; inputType: GraphQLInputType; typeVal: TypeVal } {
      let inputType: GraphQLInputType;
      let outputType: GraphQLOutputType;
      let typeVal: TypeVal;
      switch (functionType.type) {
        case SyntaxType.BinaryKeyword:
        case SyntaxType.StringKeyword:
          inputType = GraphQLString;
          outputType = GraphQLString;
          break;
        case SyntaxType.DoubleKeyword:
          inputType = GraphQLFloat;
          outputType = GraphQLFloat;
          typeVal = typeVal! || { type: TType.DOUBLE };
          break;
        case SyntaxType.VoidKeyword:
          typeVal = typeVal! || { type: TType.VOID };
          inputType = GraphQLVoid;
          outputType = GraphQLVoid;
          break;
        case SyntaxType.BoolKeyword:
          typeVal = typeVal! || { type: TType.BOOL };
          inputType = GraphQLBoolean;
          outputType = GraphQLBoolean;
          break;
        case SyntaxType.I8Keyword:
          inputType = GraphQLInt;
          outputType = GraphQLInt;
          typeVal = typeVal! || { type: TType.I08 };
          break;
        case SyntaxType.I16Keyword:
          inputType = GraphQLInt;
          outputType = GraphQLInt;
          typeVal = typeVal! || { type: TType.I16 };
          break;
        case SyntaxType.I32Keyword:
          inputType = GraphQLInt;
          outputType = GraphQLInt;
          typeVal = typeVal! || { type: TType.I32 };
          break;
        case SyntaxType.ByteKeyword:
          inputType = GraphQLByte;
          outputType = GraphQLByte;
          typeVal = typeVal! || { type: TType.BYTE };
          break;
        case SyntaxType.I64Keyword:
          inputType = GraphQLBigInt;
          outputType = GraphQLBigInt;
          typeVal = typeVal! || { type: TType.I64 };
          break;
        case SyntaxType.ListType: {
          const ofTypeList = getGraphQLFunctionType(functionType.valueType, id);
          inputType = new GraphQLList(ofTypeList.inputType);
          outputType = new GraphQLList(ofTypeList.outputType);
          typeVal = typeVal! || { type: TType.LIST, elementType: ofTypeList.typeVal };
          break;
        }
        case SyntaxType.SetType: {
          const ofSetType = getGraphQLFunctionType(functionType.valueType, id);
          inputType = new GraphQLList(ofSetType.inputType);
          outputType = new GraphQLList(ofSetType.outputType);
          typeVal = typeVal! || { type: TType.SET, elementType: ofSetType.typeVal };
          break;
        }
        case SyntaxType.MapType: {
          inputType = GraphQLJSON;
          outputType = GraphQLJSON;
          const ofTypeKey = getGraphQLFunctionType(functionType.keyType, id);
          const ofTypeValue = getGraphQLFunctionType(functionType.valueType, id);
          typeVal = typeVal! || { type: TType.MAP, keyType: ofTypeKey.typeVal, valType: ofTypeValue.typeVal };
          break;
        }
        case SyntaxType.Identifier: {
          const typeName = functionType.value;
          if (enumTypeMap.has(typeName)) {
            const enumType = enumTypeMap.get(typeName)!;
            inputType = enumType;
            outputType = enumType;
          }
          if (inputTypeMap.has(typeName)) {
            inputType = inputTypeMap.get(typeName)!;
          }
          if (outputTypeMap.has(typeName)) {
            outputType = outputTypeMap.get(typeName)!;
          }
          typeVal = topTypeMap[typeName];
          break;
        }
        default:
          throw new Error(`Unknown function type: ${util.inspect(functionType)}!`);
      }
      return {
        inputType: inputType!,
        outputType: outputType!,
        typeVal: {
          ...typeVal!,
          id,
        },
      };
    }

    const { args: commonArgs, contextVariables } = parseInterpolationStrings(Object.values(operationHeaders || {}));

    const headersFactory = getInterpolatedHeadersFactory(operationHeaders);

    for (const statement of thriftAST.body) {
      switch (statement.type) {
        case SyntaxType.EnumDefinition:
          enumTypeMap.set(
            statement.name.value,
            new GraphQLEnumType({
              name: statement.name.value,
              description: processComments(statement.comments),
              values: statement.members.reduce(
                (prev, curr) => ({
                  ...prev,
                  [curr.name.value]: {
                    description: processComments(curr.comments),
                    value: curr.name.value,
                  },
                }),
                {} as GraphQLEnumValueConfigMap
              ),
            })
          );
          break;
        case SyntaxType.StructDefinition: {
          const structName = statement.name.value;
          const description = processComments(statement.comments);
          const objectFields: GraphQLFieldConfigMap<any, any> = {};
          const inputObjectFields: GraphQLInputFieldConfigMap = {};
          const structTypeVal: StructTypeVal = {
            id: Math.random(),
            name: structName,
            type: TType.STRUCT,
            fields: {},
          };
          topTypeMap[structName] = structTypeVal;
          const structFieldTypeMap = structTypeVal.fields;
          for (const field of statement.fields) {
            const fieldName = field.name.value;
            let fieldOutputType: GraphQLOutputType;
            let fieldInputType: GraphQLInputType;
            const description = processComments(field.comments);
            const processedFieldTypes = getGraphQLFunctionType(field.fieldType, field.fieldID?.value);
            fieldOutputType = processedFieldTypes.outputType;
            fieldInputType = processedFieldTypes.inputType;

            if (field.requiredness === 'required') {
              fieldOutputType = new GraphQLNonNull(fieldOutputType);
              fieldInputType = new GraphQLNonNull(fieldInputType);
            }

            objectFields[fieldName] = {
              type: fieldOutputType,
              description,
            };
            inputObjectFields[fieldName] = {
              type: fieldInputType,
              description,
            };
            structFieldTypeMap[fieldName] = processedFieldTypes.typeVal;
          }
          outputTypeMap.set(
            structName,
            new GraphQLObjectType({
              name: structName,
              description,
              fields: objectFields,
            })
          );
          inputTypeMap.set(
            structName,
            new GraphQLInputObjectType({
              name: structName + 'Input',
              description,
              fields: inputObjectFields,
            })
          );
          break;
        }
        case SyntaxType.ServiceDefinition:
          for (const fnIndex in statement.functions) {
            const fn = statement.functions[fnIndex];
            const fnName = fn.name.value;
            const description = processComments(fn.comments);
            const { outputType: returnType } = getGraphQLFunctionType(fn.returnType, Number(fnIndex) + 1);
            const args: GraphQLFieldConfigArgumentMap = {};
            for (const argName in commonArgs) {
              const typeNameOrType = commonArgs[argName].type;
              args[argName] = {
                type:
                  typeof typeNameOrType === 'string' ? inputTypeMap.get(typeNameOrType) : typeNameOrType || GraphQLID,
              };
            }
            const fieldTypeMap: TypeMap = {};
            for (const field of fn.fields) {
              const fieldName = field.name.value;
              const fieldDescription = processComments(field.comments);
              let { inputType: fieldType, typeVal } = getGraphQLFunctionType(field.fieldType, field.fieldID?.value);
              if (field.requiredness === 'required') {
                fieldType = new GraphQLNonNull(fieldType);
              }
              args[fieldName] = {
                type: fieldType,
                description: fieldDescription,
              };
              fieldTypeMap[fieldName] = typeVal;
            }
            rootFields[fnName] = {
              type: returnType,
              description,
              args,
              resolve: async (root, args, context, info) =>
                thriftHttpClient.doRequest(fnName, args, fieldTypeMap, {
                  headers: headersFactory({ root, args, context, info, env: process.env }),
                }),
            };
            methodNames.push(fnName);
            methodAnnotations[fnName] = { annotations: {}, fieldAnnotations: {} };
            methodParameters[fnName] = fn.fields.length + 1;
          }
          break;
        case SyntaxType.TypedefDefinition: {
          const { inputType, outputType } = getGraphQLFunctionType(statement.definitionType, Math.random());
          const typeName = statement.name.value;
          inputTypeMap.set(typeName, inputType);
          outputTypeMap.set(typeName, outputType);
          break;
        }
      }
    }

    const queryObjectType = new GraphQLObjectType({
      name: 'Query',
      fields: rootFields,
    });

    const schema = new GraphQLSchema({
      query: queryObjectType,
    });

    return {
      schema,
      contextVariables,
    };
  }
Example #14
Source File: getJSONSchemaOptionsFromRAMLOptions.ts    From graphql-mesh with MIT License 4 votes vote down vote up
/**
 * Generates the options for JSON Schema Loader
 * from RAML Loader options by extracting the JSON Schema references
 * from RAML API Document
 */
export async function getJSONSchemaOptionsFromRAMLOptions({
  ramlFilePath,
  cwd: ramlFileCwd = process.cwd(),
  operations: extraOperations,
  baseUrl: forcedBaseUrl,
  fetch = crossUndiciFetch,
  schemaHeaders = {},
  selectQueryOrMutationField = [],
}: RAMLLoaderOptions): Promise<{
  operations: JSONSchemaOperationConfig[];
  cwd: string;
  baseUrl: string;
  fetch?: WindowOrWorkerGlobalScope['fetch'];
}> {
  const fieldTypeMap: Record<string, 'query' | 'mutation'> = {};
  for (const { fieldName, type } of selectQueryOrMutationField) {
    fieldTypeMap[fieldName] = type;
  }
  const operations = extraOperations || [];
  const ramlAbsolutePath = getAbsolutePath(ramlFilePath, ramlFileCwd);
  const schemaHeadersFactory = getInterpolatedHeadersFactory(schemaHeaders);
  const ramlAPI = (await loadApi(ramlAbsolutePath, [], {
    httpResolver: {
      getResourceAsync: async (url: string) => {
        const fetchResponse = await fetch(url, {
          headers: schemaHeadersFactory({ env: process.env }),
        });
        const content = await fetchResponse.text();
        if (fetchResponse.status !== 200) {
          return {
            errorMessage: content,
          };
        }
        return {
          content,
        };
      },
      getResource: () => {
        throw new Error(`Sync fetching not available for URLs`);
      },
    },
  })) as api10.Api;
  let baseUrl = forcedBaseUrl;
  if (!baseUrl) {
    baseUrl = ramlAPI.baseUri().value();
    for (const baseUrlParamNode of ramlAPI.baseUriParameters()) {
      const paramName = baseUrlParamNode.name();
      baseUrl = baseUrl.split(`{${paramName}}`).join(`{context.${paramName}}`);
    }
  }
  const pathTypeMap = new Map<string, string>();
  const typePathMap = new Map<string, string>();
  for (const typeNode of ramlAPI.types()) {
    const typeNodeJson = typeNode.toJSON();
    for (const typeName in typeNodeJson) {
      const { schemaPath } = typeNodeJson[typeName];
      if (schemaPath) {
        pathTypeMap.set(schemaPath, typeName);
        typePathMap.set(typeName, schemaPath);
      }
    }
  }
  const cwd = getCwd(ramlAbsolutePath);
  const apiQueryParameters: api10.TypeDeclaration[] = [];
  const apiBodyNodes: api10.TypeDeclaration[] = [];
  const apiResponses: api10.Response[] = [];
  for (const traitNode of ramlAPI.traits()) {
    apiQueryParameters.push(...traitNode.queryParameters());
    apiBodyNodes.push(...traitNode.body());
    apiResponses.push(...traitNode.responses());
    const nestedTraits = resolveTraitsByIs(traitNode);
    for (const nestedTrait of nestedTraits) {
      apiQueryParameters.push(...nestedTrait.queryParameters());
      apiBodyNodes.push(...nestedTrait.body());
      apiResponses.push(...nestedTrait.responses());
    }
  }
  for (const resourceNode of ramlAPI.allResources()) {
    const resourceQueryParameters: api10.TypeDeclaration[] = [...apiQueryParameters];
    const resourceBodyNodes: api10.TypeDeclaration[] = [...apiBodyNodes];
    const resourceResponses: api10.Response[] = [...apiResponses];
    const resourceTraits = resolveTraitsByIs(resourceNode);
    for (const traitNode of resourceTraits) {
      apiQueryParameters.push(...traitNode.queryParameters());
      apiBodyNodes.push(...traitNode.body());
      apiResponses.push(...traitNode.responses());
    }
    for (const methodNode of resourceNode.methods()) {
      const queryParameters: api10.TypeDeclaration[] = [...resourceQueryParameters];
      const bodyNodes: api10.TypeDeclaration[] = [...resourceBodyNodes];
      const responses: api10.Response[] = [...resourceResponses];
      const traits = resolveTraitsByIs(methodNode);
      for (const traitNode of traits) {
        queryParameters.push(...traitNode.queryParameters());
        bodyNodes.push(...traitNode.body());
        responses.push(...traitNode.responses());
      }
      queryParameters.push(...methodNode.queryParameters());
      bodyNodes.push(...methodNode.body());
      responses.push(...methodNode.responses());
      let requestSchema: string | JSONSchemaObject;
      let requestTypeName: string;
      const responseByStatusCode: Record<string, JSONSchemaOperationResponseConfig> = {};
      const method = methodNode.method().toUpperCase() as HTTPMethod;
      let fieldName = methodNode.displayName()?.replace('GET_', '');
      const description = methodNode.description()?.value() || resourceNode.description()?.value();
      const originalFullRelativeUrl = resourceNode.completeRelativeUri();
      let fullRelativeUrl = originalFullRelativeUrl;
      const argTypeMap: Record<string, string | GraphQLInputType> = {};
      for (const uriParameterNode of resourceNode.uriParameters()) {
        const paramName = uriParameterNode.name();
        fullRelativeUrl = fullRelativeUrl.replace(`{${paramName}}`, `{args.${paramName}}`);
        const uriParameterNodeJson = uriParameterNode.toJSON();
        for (const typeName of asArray(uriParameterNodeJson.type)) {
          switch (typeName) {
            case 'number':
              argTypeMap[paramName] = 'Float';
              break;
            case 'boolean':
              argTypeMap[paramName] = 'Boolean';
              break;
            case 'integer':
              argTypeMap[paramName] = 'Int';
              break;
            default:
              argTypeMap[paramName] = 'String';
              break;
          }
        }
        /* raml pattern is different
        if (uriParameterNodeJson.pattern) {
          const typeName = sanitizeNameForGraphQL(uriParameterNodeJson.displayName || `${fieldName}_${paramName}`);
          argTypeMap[paramName] = new RegularExpression(typeName, new RegExp(uriParameterNodeJson.pattern), {
            description: uriParameterNodeJson.description,
          });
        }
        */
        if (uriParameterNodeJson.enum) {
          const typeName = sanitizeNameForGraphQL(uriParameterNodeJson.displayName || `${fieldName}_${paramName}`);
          const values: GraphQLEnumValueConfigMap = {};
          for (const value of asArray(uriParameterNodeJson.enum)) {
            let enumKey = sanitizeNameForGraphQL(value.toString());
            if (enumKey === 'false' || enumKey === 'true' || enumKey === 'null') {
              enumKey = enumKey.toUpperCase();
            }
            if (typeof enumKey === 'string' && enumKey.length === 0) {
              enumKey = '_';
            }
            values[enumKey] = {
              // Falsy values are ignored by GraphQL
              // eslint-disable-next-line no-unneeded-ternary
              value: value ? value : value?.toString(),
            };
          }
          argTypeMap[paramName] = new GraphQLEnumType({
            name: typeName,
            description: uriParameterNodeJson.description,
            values,
          });
        }
        if (uriParameterNodeJson.required) {
          argTypeMap[paramName] += '!';
        }
      }
      for (const queryParameterNode of queryParameters) {
        requestSchema = requestSchema || {
          type: 'object',
          properties: {},
          required: [],
        };
        const parameterName = queryParameterNode.name();
        const queryParameterNodeJson = queryParameterNode.toJSON();
        if (queryParameterNodeJson.required) {
          (requestSchema as JSONSchemaObject).required.push(parameterName);
        }
        if (queryParameterNodeJson.enum) {
          (requestSchema as JSONSchemaObject).properties[parameterName] = {
            type: 'string',
            enum: queryParameterNodeJson.enum,
          };
        }
        if (queryParameterNodeJson.type) {
          (requestSchema as JSONSchemaObject).properties[parameterName] = {
            type: asArray(queryParameterNodeJson.type)[0] || 'string',
          };
        } else {
          (requestSchema as JSONSchemaObject).properties[parameterName] = toJsonSchema(
            queryParameterNodeJson.example ?? queryParameterNodeJson.default,
            {
              required: false,
              strings: {
                detectFormat: true,
              },
            }
          );
        }
        if (queryParameterNodeJson.displayName) {
          (requestSchema as JSONSchemaObject).properties[parameterName].title = queryParameterNodeJson.displayName;
        }
        if (queryParameterNode.description) {
          (requestSchema as JSONSchemaObject).properties[parameterName].description =
            queryParameterNodeJson.description;
        }
      }

      for (const bodyNode of bodyNodes) {
        if (bodyNode.name().includes('application/json')) {
          const bodyJson = bodyNode.toJSON();
          if (bodyJson.schemaPath) {
            const schemaPath = bodyJson.schemaPath;
            requestSchema = schemaPath;
            requestTypeName = pathTypeMap.get(schemaPath);
          } else if (bodyJson.type) {
            const typeName = asArray(bodyJson.type)[0];
            requestTypeName = typeName;
            const schemaPath = typePathMap.get(typeName);
            requestSchema = schemaPath;
          }
        }
      }
      for (const responseNode of responses) {
        const statusCode = responseNode.code().value();
        const responseNodeDescription = responseNode.description()?.value();
        for (const bodyNode of responseNode.body()) {
          if (bodyNode.name().includes('application/json')) {
            const bodyJson = bodyNode.toJSON();
            if (bodyJson.schemaPath) {
              const schemaPath = bodyJson.schemaPath;
              const typeName = pathTypeMap.get(schemaPath);
              if (schemaPath) {
                responseByStatusCode[statusCode] = {
                  responseSchema: schemaPath,
                  responseTypeName: typeName,
                };
              }
            } else if (bodyJson.type) {
              const typeName = asArray(bodyJson.type)[0];
              const schemaPath = typePathMap.get(typeName);
              if (schemaPath) {
                responseByStatusCode[statusCode] = {
                  responseSchema: schemaPath,
                  responseTypeName: typeName,
                };
              }
            }
            if (!responseByStatusCode[statusCode] && bodyJson.example) {
              const responseSchema = toJsonSchema(bodyJson.example, {
                required: false,
              }) as any;
              responseSchema.description = responseNodeDescription;
              responseByStatusCode[statusCode] = {
                responseSchema,
              };
            }
          }
        }
      }
      fieldName =
        fieldName ||
        getFieldNameFromPath(originalFullRelativeUrl, method, responseByStatusCode['200']?.responseTypeName);
      if (fieldName) {
        const graphQLFieldName = sanitizeNameForGraphQL(fieldName);
        const operationType: any = fieldTypeMap[graphQLFieldName] ?? method === 'GET' ? 'query' : 'mutation';
        operations.push({
          type: operationType,
          field: graphQLFieldName,
          description,
          path: fullRelativeUrl,
          method,
          requestSchema,
          requestTypeName,
          responseByStatusCode,
          argTypeMap,
        });
      }
    }
  }
  return {
    operations,
    baseUrl,
    cwd,
    fetch,
  };
}