relay-runtime
Version:
A core runtime for building GraphQL-driven applications.
203 lines (185 loc) • 5.22 kB
Flow
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @oncall relay
*/
;
import type {
ReaderFragment,
ReaderInlineDataFragment,
ReaderPaginationFragment,
ReaderRefetchableFragment,
} from '../util/ReaderNode';
import type {
ConcreteRequest,
ConcreteUpdatableQuery,
} from '../util/RelayConcreteNode';
const RelayConcreteNode = require('../util/RelayConcreteNode');
const invariant = require('invariant');
const warning = require('warning');
// The type of a graphql`...` tagged template expression.
export type GraphQLTaggedNode =
| ReaderFragment
| ReaderInlineDataFragment
| ConcreteRequest
| ConcreteUpdatableQuery
| {
// This is this case when we `require()` a generated ES6 module
default:
| ReaderFragment
| ReaderInlineDataFragment
| ConcreteRequest
| ConcreteUpdatableQuery,
...
};
/**
* Runtime function to correspond to the `graphql` tagged template function.
* All calls to this function should be transformed by the plugin.
*/
function graphql(strings: $ReadOnlyArray<string>): any {
invariant(
false,
'graphql: Unexpected invocation at runtime. Either the Babel transform ' +
'was not set up, or it failed to identify this call site. Make sure it ' +
'is being used verbatim as `graphql`. Note also that there cannot be ' +
'a space between graphql and the backtick that follows.',
);
}
function getNode(
taggedNode: GraphQLTaggedNode,
):
| ReaderFragment
| ReaderInlineDataFragment
| ConcreteRequest
| ConcreteUpdatableQuery {
let node = taggedNode;
if (typeof node === 'function') {
node = (node(): ReaderFragment | ConcreteRequest);
warning(
false,
'RelayGraphQLTag: node `%s` unexpectedly wrapped in a function.',
node.kind === 'Fragment' ? node.name : node.operation.name,
);
} else if (node.default) {
// Support for languages that work (best) with ES6 modules, such as TypeScript.
node = node.default;
}
return node;
}
function isFragment(node: GraphQLTaggedNode): boolean {
const fragment = getNode(node);
return (
typeof fragment === 'object' &&
fragment !== null &&
fragment.kind === RelayConcreteNode.FRAGMENT
);
}
function isRequest(node: GraphQLTaggedNode): boolean {
const request = getNode(node);
return (
typeof request === 'object' &&
request !== null &&
request.kind === RelayConcreteNode.REQUEST
);
}
function isUpdatableQuery(node: GraphQLTaggedNode): boolean {
const updatableQuery = getNode(node);
return (
typeof updatableQuery === 'object' &&
updatableQuery !== null &&
updatableQuery.kind === RelayConcreteNode.UPDATABLE_QUERY
);
}
function isInlineDataFragment(node: GraphQLTaggedNode): boolean {
const fragment = getNode(node);
return (
typeof fragment === 'object' &&
fragment !== null &&
fragment.kind === RelayConcreteNode.INLINE_DATA_FRAGMENT
);
}
function getFragment(taggedNode: GraphQLTaggedNode): ReaderFragment {
const fragment = getNode(taggedNode);
invariant(
isFragment(fragment),
'GraphQLTag: Expected a fragment, got `%s`.',
JSON.stringify(fragment),
);
return (fragment: any);
}
function getPaginationFragment(
taggedNode: GraphQLTaggedNode,
): ReaderPaginationFragment | null {
const fragment = getFragment(taggedNode);
const refetch = fragment.metadata?.refetch;
const connection = refetch?.connection;
if (
refetch === null ||
typeof refetch !== 'object' ||
connection === null ||
typeof connection !== 'object'
) {
return null;
}
return (fragment: any);
}
function getRefetchableFragment(
taggedNode: GraphQLTaggedNode,
): ReaderRefetchableFragment | null {
const fragment = getFragment(taggedNode);
const refetch = fragment.metadata?.refetch;
if (refetch === null || typeof refetch !== 'object') {
return null;
}
return (fragment: any);
}
function getRequest(taggedNode: GraphQLTaggedNode): ConcreteRequest {
const request = getNode(taggedNode);
invariant(
isRequest(request),
'GraphQLTag: Expected a request, got `%s`.',
JSON.stringify(request),
);
return (request: any);
}
function getUpdatableQuery(
taggedNode: GraphQLTaggedNode,
): ConcreteUpdatableQuery {
const updatableQuery = getNode(taggedNode);
invariant(
isUpdatableQuery(updatableQuery),
'GraphQLTag: Expected a request, got `%s`.',
JSON.stringify(updatableQuery),
);
return (updatableQuery: any);
}
function getInlineDataFragment(
taggedNode: GraphQLTaggedNode,
): ReaderInlineDataFragment {
const fragment = getNode(taggedNode);
invariant(
isInlineDataFragment(fragment),
'GraphQLTag: Expected an inline data fragment, got `%s`.',
JSON.stringify(fragment),
);
return (fragment: any);
}
module.exports = {
getFragment,
getNode,
getPaginationFragment,
getRefetchableFragment,
getRequest,
getUpdatableQuery,
getInlineDataFragment,
graphql,
isFragment,
isRequest,
isUpdatableQuery,
isInlineDataFragment,
};