@ardatan/relay-compiler
Version:
A compiler tool for building GraphQL-driven applications.
185 lines (168 loc) • 4.93 kB
Flow
/**
* 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
*/
// flowlint ambiguous-object-type:error
;
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 => BabelNode_DEPRECATED),
...,
};
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?: BabelNode_DEPRECATED,
): BabelNode_DEPRECATED {
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,
): BabelNode_DEPRECATED {
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,
): BabelNode_DEPRECATED {
state.usedEnums[schema.getTypeString(type)] = type;
return t.genericTypeAnnotation(t.identifier(schema.getTypeString(type)));
}
function transformInputType(
schema: Schema,
type: TypeID,
state: State,
): BabelNode_DEPRECATED {
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,
): BabelNode_DEPRECATED {
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,
};