Files
30-seconds-of-code/node_modules/@gatsbyjs/relay-compiler/lib/SkipClientFieldTransform.js
2019-08-20 15:52:05 +02:00

191 lines
4.6 KiB
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.
*
* strict-local
* @format
*/
'use strict';
var GraphQLCompilerContext = require("./GraphQLCompilerContext");
var GraphQLIRTransformer = require("./GraphQLIRTransformer");
var invariant = require("fbjs/lib/invariant");
var _require = require("./GraphQLSchemaUtils"),
assertTypeWithFields = _require.assertTypeWithFields,
canHaveSelections = _require.canHaveSelections,
getRawType = _require.getRawType;
var _require2 = require("graphql"),
SchemaMetaFieldDef = _require2.SchemaMetaFieldDef,
TypeMetaFieldDef = _require2.TypeMetaFieldDef,
TypeNameMetaFieldDef = _require2.TypeNameMetaFieldDef;
/**
* A transform that removes any selections that are not valid relative to the
* server schema. The primary use case is for fields added via client
* `extend type ...` definitions and for inline fragments / fragment spreads
* whose types are added with client `type ...` type extensions.
*
* Given a base schema:
*
* ```
* # Note: full schema definition elided for clarity
* interface Viewer {
* name: String
* }
* type User implements Viewer {
* name: String
* }
* ```
*
* And a fragment:
*
* ```
* fragment on Viewer {
* name
* ... on User {
* clientField # (1)
* }
* ... on ClientType { # (2)
* clientField
* }
* }
* extend type User {
* clientField: String
* }
* type ClientType implements Viewer {
* name: String
* clientField: String
* }
* ```
*
* This transform will output:
*
* ```
* fragment on Viewer {
* name
* }
* ```
*
* Note that (1) is removed because this field does not exist on the base `User`
* type, and (2) is removed because the `ClientType` type does not exist in the
* base schema.
*/
function skipClientFieldTransform(context) {
return GraphQLIRTransformer.transform(context, {
FragmentSpread: visitFragmentSpread,
InlineFragment: visitInlineFragment,
LinkedField: visitField,
MatchField: visitField,
ScalarField: visitField
}, function (node) {
return buildState(context, node);
});
}
/**
* @internal
*
* Build the initial state, returning null for fragments whose type is not
* defined in the server schema.
*/
function buildState(context, node) {
var schema = context.serverSchema;
switch (node.kind) {
case 'Fragment':
return schema.getType(node.type.name);
case 'Root':
switch (node.operation) {
case 'query':
return schema.getQueryType();
case 'mutation':
return schema.getMutationType();
case 'subscription':
return schema.getSubscriptionType();
default:
node.operation;
}
break;
case 'SplitOperation':
return schema.getType(node.type.name);
default:
node;
}
return null;
}
/**
* @internal
*
* Skip fields that were added via `extend type ...`.
*/
function visitField(field, parentType) {
if ( // Field is defined in the original parent type definition:
canHaveSelections(parentType) && assertTypeWithFields(parentType).getFields()[field.name] || // Allow metadata fields and fields defined on classic "fat" interfaces
field.name === SchemaMetaFieldDef.name || field.name === TypeMetaFieldDef.name || field.name === TypeNameMetaFieldDef.name || field.directives.some(function (_ref) {
var name = _ref.name;
return name === 'fixme_fat_interface';
})) {
var rawType = getRawType(field.type);
var type = this.getContext().serverSchema.getType(rawType.name);
!type ? process.env.NODE_ENV !== "production" ? invariant(false, 'SkipClientFieldTransform: Expected type `%s` to be defined in ' + 'the server schema.', rawType.name) : invariant(false) : void 0;
return this.traverse(field, type);
}
return null;
}
/**
* @internal
*
* Skip fragment spreads where the referenced fragment is not defined in the
* original schema.
*/
function visitFragmentSpread(spread, parentType) {
var context = this.getContext();
var fragment = context.getFragment(spread.name);
if (context.serverSchema.getType(fragment.type.name)) {
return this.traverse(spread, parentType);
}
return null;
}
/**
* @internal
*
* Skip inline fragments where the type is not in the schema.
*/
function visitInlineFragment(fragment, parentType) {
var schema = this.getContext().serverSchema;
var type = schema.getType(fragment.typeCondition.name);
if (type) {
return this.traverse(fragment, type);
}
return null;
}
module.exports = {
transform: skipClientFieldTransform
};