text: /**
   * Copyright (c) Facebook, Inc. and its affiliates.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   *
   * @flow strict-local
   * @format
   */
  
  'use strict';
  
  const t = require('@babel/types');
  
  const {
    exactObjectTypeAnnotation,
    readOnlyArrayOfType,
  } = require('./RelayFlowBabelFactories');
  
  import type {Schema, TypeID, EnumTypeID} from '../../core/Schema';
  
  export type BabelTypes = typeof t;
  export type ScalarTypeMapping = {
    [type: string]: string | (BabelTypes => mixed),
  };
  
  import type {State} from './RelayFlowGenerator';
  
  function getInputObjectTypeIdentifier(schema: Schema, typeID: TypeID): string {
    return schema.getTypeString(typeID);
  }
  
  function transformScalarType(
    schema: Schema,
    type: TypeID,
    state: State,
    objectProps?: mixed,
  ): mixed {
    if (schema.isNonNull(type)) {
      return transformNonNullableScalarType(
        schema,
        schema.getNullableType(type),
        state,
        objectProps,
      );
    } else {
      return t.nullableTypeAnnotation(
        transformNonNullableScalarType(schema, type, state, objectProps),
      );
    }
  }
  
  function transformNonNullableScalarType(
    schema: Schema,
    type: TypeID,
    state: State,
    objectProps,
  ) {
    if (schema.isList(type)) {
      return readOnlyArrayOfType(
        transformScalarType(
          schema,
          schema.getListItemType(type),
          state,
          objectProps,
        ),
      );
    } else if (
      schema.isObject(type) ||
      schema.isUnion(type) ||
      schema.isInterface(type)
    ) {
      return objectProps;
    } else if (schema.isScalar(type)) {
      return transformGraphQLScalarType(schema.getTypeString(type), state);
    } else if (schema.isEnum(type)) {
      return transformGraphQLEnumType(schema, schema.assertEnumType(type), state);
    } else {
      throw new Error(`Could not convert from GraphQL type ${String(type)}`);
    }
  }
  
  function transformGraphQLScalarType(typeName: string, state: State) {
    const customType = state.customScalars[typeName];
    if (typeof customType === 'function') {
      return customType(t);
    }
    switch (customType ?? typeName) {
      case 'ID':
      case 'String':
        return t.stringTypeAnnotation();
      case 'Float':
      case 'Int':
        return t.numberTypeAnnotation();
      case 'Boolean':
        return t.booleanTypeAnnotation();
      default:
        return customType == null
          ? t.anyTypeAnnotation()
          : t.genericTypeAnnotation(t.identifier(customType));
    }
  }
  
  function transformGraphQLEnumType(
    schema: Schema,
    type: EnumTypeID,
    state: State,
  ) {
    state.usedEnums[schema.getTypeString(type)] = type;
    return t.genericTypeAnnotation(t.identifier(schema.getTypeString(type)));
  }
  
  function transformInputType(
    schema: Schema,
    type: TypeID,
    state: State,
  ): $FlowFixMe {
    if (schema.isNonNull(type)) {
      return transformNonNullableInputType(
        schema,
        schema.getNullableType(type),
        state,
      );
    } else {
      return t.nullableTypeAnnotation(
        transformNonNullableInputType(schema, type, state),
      );
    }
  }
  
  function transformNonNullableInputType(
    schema: Schema,
    type: TypeID,
    state: State,
  ) {
    if (schema.isList(type)) {
      return readOnlyArrayOfType(
        transformInputType(schema, schema.getListItemType(type), state),
      );
    } else if (schema.isScalar(type)) {
      return transformGraphQLScalarType(schema.getTypeString(type), state);
    } else if (schema.isEnum(type)) {
      return transformGraphQLEnumType(schema, schema.assertEnumType(type), state);
    } else if (schema.isInputObject(type)) {
      const typeIdentifier = getInputObjectTypeIdentifier(schema, type);
      if (state.generatedInputObjectTypes[typeIdentifier]) {
        return t.genericTypeAnnotation(t.identifier(typeIdentifier));
      }
      state.generatedInputObjectTypes[typeIdentifier] = 'pending';
      const fields = schema.getFields(schema.assertInputObjectType(type));
      const props = fields.map(fieldID => {
        const fieldType = schema.getFieldType(fieldID);
        const fieldName = schema.getFieldName(fieldID);
        const property = t.objectTypeProperty(
          t.identifier(fieldName),
          transformInputType(schema, fieldType, state),
        );
        if (
          state.optionalInputFields.indexOf(fieldName) >= 0 ||
          !schema.isNonNull(fieldType)
        ) {
          property.optional = true;
        }
        return property;
      });
  
      state.generatedInputObjectTypes[typeIdentifier] = exactObjectTypeAnnotation(
        props,
      );
      return t.genericTypeAnnotation(t.identifier(typeIdentifier));
    } else {
      throw new Error(
        `Could not convert from GraphQL type ${schema.getTypeString(type)}`,
      );
    }
  }
  
  module.exports = {
    transformInputType,
    transformScalarType,
  };
  