-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Expand file tree
/
Copy pathRelayRelayDirectiveTransform.js
More file actions
107 lines (93 loc) · 3.11 KB
/
RelayRelayDirectiveTransform.js
File metadata and controls
107 lines (93 loc) · 3.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/**
* 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 IRTransformer = require('../core/GraphQLIRTransformer');
const getLiteralArgumentValues = require('../core/getLiteralArgumentValues');
const invariant = require('invariant');
import type CompilerContext from '../core/GraphQLCompilerContext';
import type {Fragment, FragmentSpread} from '../core/GraphQLIR';
const RELAY = 'relay';
const SCHEMA_EXTENSION = `
directive @relay(
# Marks a connection field as containing nodes without 'id' fields.
# This is used to silence the warning when diffing connections.
isConnectionWithoutNodeID: Boolean,
# Marks a fragment as intended for pattern matching (as opposed to fetching).
# Used in Classic only.
pattern: Boolean,
# Marks a fragment as being backed by a GraphQLList.
plural: Boolean,
# Marks a fragment spread which should be unmasked if provided false
mask: Boolean = true,
# Selectively pass variables down into a fragment. Only used in Classic.
variables: [String!],
) on FRAGMENT_DEFINITION | FRAGMENT_SPREAD | INLINE_FRAGMENT | FIELD
`;
/**
* A transform that extracts `@relay(plural: Boolean)` directives and converts
* them to metadata that can be accessed at runtime.
*/
function relayRelayDirectiveTransform(
context: CompilerContext,
): CompilerContext {
return IRTransformer.transform(context, {
Fragment: visitRelayMetadata(fragmentMetadata),
FragmentSpread: visitRelayMetadata(fragmentSpreadMetadata),
});
}
type MixedObj = {[key: string]: mixed};
function visitRelayMetadata<T: Fragment | FragmentSpread>(
metadataFn: MixedObj => MixedObj,
): T => T {
return function(node) {
const relayDirective = node.directives.find(({name}) => name === RELAY);
if (!relayDirective) {
return this.traverse(node);
}
const argValues = getLiteralArgumentValues(relayDirective.args);
const metadata = metadataFn(argValues);
return this.traverse({
...node,
directives: node.directives.filter(
directive => directive !== relayDirective,
),
metadata: {
...(node.metadata || {}),
...metadata,
},
});
};
}
function fragmentMetadata({mask, plural}): MixedObj {
invariant(
plural === undefined || typeof plural === 'boolean',
'RelayRelayDirectiveTransform: Expected the "plural" argument to @relay ' +
'to be a boolean literal if specified.',
);
invariant(
mask === undefined || typeof mask === 'boolean',
'RelayRelayDirectiveTransform: Expected the "mask" argument to @relay ' +
'to be a boolean literal if specified.',
);
return {mask, plural};
}
function fragmentSpreadMetadata({mask}): MixedObj {
invariant(
mask === undefined || typeof mask === 'boolean',
'RelayRelayDirectiveTransform: Expected the "mask" argument to @relay ' +
'to be a boolean literal if specified.',
);
return {mask};
}
module.exports = {
RELAY,
SCHEMA_EXTENSION,
transform: relayRelayDirectiveTransform,
};