@ardatan/relay-compiler
Version:
A compiler tool for building GraphQL-driven applications.
161 lines (135 loc) • 5.88 kB
JavaScript
/**
* 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.
*
*
* @format
* @emails oncall+relay
*/
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
var IRTransformer = require('../core/IRTransformer');
var _require = require('../core/CompilerError'),
createUserError = _require.createUserError,
createCompilerError = _require.createCompilerError;
var _require2 = require('relay-runtime'),
RelayFeatureFlags = _require2.RelayFeatureFlags;
var FLIGHT_FIELD_COMPONENT_ARGUMENT_TYPE = 'String';
var FLIGHT_FIELD_COMPONENT_ARGUMENT_NAME = 'component';
var FLIGHT_FIELD_PROPS_ARGUMENT_NAME = 'props';
var FLIGHT_FIELD_PROPS_TYPE = 'ReactFlightProps';
var FLIGHT_FIELD_RETURN_TYPE = 'ReactFlightComponent';
/**
* Experimental transform for React Flight.
*/
function reactFlightComponentTransform(context) {
var schema = context.getSchema();
var propsType = schema.getTypeFromString(FLIGHT_FIELD_PROPS_TYPE);
propsType = propsType ? schema.asInputType(propsType) : null;
var componentType = schema.getTypeFromString(FLIGHT_FIELD_RETURN_TYPE);
componentType = componentType ? schema.asScalarFieldType(componentType) : null;
if (!RelayFeatureFlags.ENABLE_REACT_FLIGHT_COMPONENT_FIELD || propsType == null || componentType == null) {
return context;
}
var types = {
propsType: propsType,
componentType: componentType
};
return IRTransformer.transform(context, {
ScalarField: visitScalarField,
LinkedField: visitLinkedField,
InlineFragment: visitInlineFragment
}, function (node) {
return {
parentType: node.type,
types: types
};
});
}
function visitInlineFragment(fragment, state) {
var _fragment$typeConditi;
// $FlowFixMe[incompatible-use]
return this.traverse(fragment, {
parentType: (_fragment$typeConditi = fragment.typeCondition) !== null && _fragment$typeConditi !== void 0 ? _fragment$typeConditi : state.parentType,
types: state.types
});
}
function visitLinkedField(field, state) {
// $FlowFixMe[incompatible-use]
return this.traverse(field, {
parentType: field.type,
types: state.types
});
}
function visitScalarField(field, state) {
// use the return type to quickly determine if this is a flight field
// $FlowFixMe[incompatible-use]
var schema = this.getContext().getSchema();
if (schema.getRawType(field.type) !== state.types.componentType) {
return field;
} // get the name of the component that provides this field
var clientField = schema.getFieldByName(state.parentType, field.name);
if (clientField == null) {
throw createCompilerError("Definition not found for field '".concat(schema.getTypeString(state.parentType), ".").concat(field.name, "'"), [field.loc]);
}
var componentDirective = clientField.directives.find(function (directive) {
return directive.name === 'react_flight_component';
});
var componentNameArg = componentDirective === null || componentDirective === void 0 ? void 0 : componentDirective.args.find(function (arg) {
return arg.name === 'name';
});
if (componentNameArg == null || componentNameArg.value.kind !== 'StringValue' || typeof componentNameArg.value.value !== 'string') {
throw createUserError('Invalid Flight field, expected the schema extension to specify ' + "the component's module name with the '@react_flight_component' directive", [field.loc]);
}
var componentName = componentNameArg.value.value; // validate that the parent type has a `flight(component, props)` field
var flightField = schema.getFieldByName(state.parentType, 'flight');
if (flightField == null) {
throw createUserError("Invalid Flight field, expected the parent type '".concat(schema.getTypeString(state.parentType), "' ") + "to define a 'flight(component: String, props: ReactFlightProps): ReactFlightComponent' field", [field.loc]);
}
var componentArg = flightField.args.get(FLIGHT_FIELD_COMPONENT_ARGUMENT_NAME);
var propsArg = flightField.args.get(FLIGHT_FIELD_PROPS_ARGUMENT_NAME);
if (componentArg == null || propsArg == null || schema.getRawType(componentArg.type) !== schema.getTypeFromString(FLIGHT_FIELD_COMPONENT_ARGUMENT_TYPE) || schema.getRawType(propsArg.type) !== state.types.propsType || schema.getRawType(flightField.type) !== state.types.componentType) {
throw createUserError("Invalid Flight field, expected the parent type '".concat(schema.getTypeString(state.parentType), "' ") + "to define a 'flight(component: String, props: ReactFlightProps): ReactFlightComponent' field", [field.loc]);
}
return (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, field), {}, {
name: 'flight',
args: [{
kind: 'Argument',
loc: field.loc,
name: FLIGHT_FIELD_COMPONENT_ARGUMENT_NAME,
type: schema.getTypeFromString(FLIGHT_FIELD_COMPONENT_ARGUMENT_TYPE),
value: {
kind: 'Literal',
value: componentName,
loc: field.loc
}
}, {
kind: 'Argument',
loc: field.loc,
name: FLIGHT_FIELD_PROPS_ARGUMENT_NAME,
type: state.types.propsType,
value: {
kind: 'ObjectValue',
fields: field.args.map(function (arg) {
return {
kind: 'ObjectFieldValue',
loc: arg.loc,
name: arg.name,
value: arg.value
};
}),
loc: field.loc
}
}],
metadata: (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, field.metadata || {}), {}, {
flight: true
}),
type: state.types.componentType
});
}
module.exports = {
transform: reactFlightComponentTransform
};