@graphql-tools/stitching-directives 3.0.0-alpha-be1b2ebd.0 → 3.0.0-alpha-20230517123108-df347e95
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +0 -2
- package/cjs/defaultStitchingDirectiveOptions.js +10 -0
- package/cjs/extractVariables.js +52 -0
- package/cjs/federationToStitchingSDL.js +114 -0
- package/cjs/getSourcePaths.js +25 -0
- package/cjs/index.js +6 -0
- package/cjs/package.json +1 -0
- package/cjs/parseMergeArgsExpr.js +69 -0
- package/cjs/pathsFromSelectionSet.js +31 -0
- package/cjs/preparseMergeArgsExpr.js +31 -0
- package/cjs/properties.js +70 -0
- package/cjs/stitchingDirectives.js +78 -0
- package/cjs/stitchingDirectivesTransformer.js +423 -0
- package/cjs/stitchingDirectivesValidator.js +120 -0
- package/cjs/types.js +0 -0
- package/esm/defaultStitchingDirectiveOptions.js +7 -0
- package/esm/extractVariables.js +48 -0
- package/esm/federationToStitchingSDL.js +110 -0
- package/esm/getSourcePaths.js +21 -0
- package/esm/index.js +3 -0
- package/esm/parseMergeArgsExpr.js +65 -0
- package/esm/pathsFromSelectionSet.js +27 -0
- package/esm/preparseMergeArgsExpr.js +27 -0
- package/esm/properties.js +63 -0
- package/esm/stitchingDirectives.js +74 -0
- package/esm/stitchingDirectivesTransformer.js +419 -0
- package/esm/stitchingDirectivesValidator.js +116 -0
- package/esm/types.js +0 -0
- package/package.json +40 -15
- package/typings/defaultStitchingDirectiveOptions.d.cts +2 -0
- package/{defaultStitchingDirectiveOptions.d.ts → typings/defaultStitchingDirectiveOptions.d.ts} +1 -1
- package/typings/extractVariables.d.cts +7 -0
- package/{extractVariables.d.ts → typings/extractVariables.d.ts} +1 -1
- package/typings/federationToStitchingSDL.d.cts +2 -0
- package/{federationToStitchingSDL.d.ts → typings/federationToStitchingSDL.d.ts} +1 -1
- package/typings/getSourcePaths.d.cts +3 -0
- package/{getSourcePaths.d.ts → typings/getSourcePaths.d.ts} +1 -1
- package/typings/index.d.cts +3 -0
- package/typings/index.d.ts +3 -0
- package/typings/parseMergeArgsExpr.d.cts +3 -0
- package/{parseMergeArgsExpr.d.ts → typings/parseMergeArgsExpr.d.ts} +1 -1
- package/typings/pathsFromSelectionSet.d.ts +2 -0
- package/typings/preparseMergeArgsExpr.d.ts +6 -0
- package/typings/properties.d.cts +5 -0
- package/{properties.d.ts → typings/properties.d.ts} +1 -1
- package/typings/stitchingDirectives.d.cts +19 -0
- package/{stitchingDirectives.d.ts → typings/stitchingDirectives.d.ts} +1 -1
- package/typings/stitchingDirectivesTransformer.d.cts +3 -0
- package/{stitchingDirectivesTransformer.d.ts → typings/stitchingDirectivesTransformer.d.ts} +1 -1
- package/typings/stitchingDirectivesValidator.d.cts +3 -0
- package/{stitchingDirectivesValidator.d.ts → typings/stitchingDirectivesValidator.d.ts} +1 -1
- package/typings/types.d.cts +35 -0
- package/{types.d.ts → typings/types.d.ts} +3 -3
- package/index.d.ts +0 -3
- package/index.js +0 -972
- package/index.mjs +0 -967
- /package/{pathsFromSelectionSet.d.ts → typings/pathsFromSelectionSet.d.cts} +0 -0
- /package/{preparseMergeArgsExpr.d.ts → typings/preparseMergeArgsExpr.d.cts} +0 -0
@@ -0,0 +1,110 @@
|
|
1
|
+
// Taken from https://github.com/gmac/federation-to-stitching-sdl/blob/main/index.js
|
2
|
+
import { print, Kind, parse, } from 'graphql';
|
3
|
+
import { stitchingDirectives } from './stitchingDirectives.js';
|
4
|
+
const extensionKind = /Extension$/;
|
5
|
+
const entityKinds = [
|
6
|
+
Kind.OBJECT_TYPE_DEFINITION,
|
7
|
+
Kind.OBJECT_TYPE_EXTENSION,
|
8
|
+
Kind.INTERFACE_TYPE_DEFINITION,
|
9
|
+
Kind.INTERFACE_TYPE_EXTENSION,
|
10
|
+
];
|
11
|
+
function isEntityKind(def) {
|
12
|
+
return entityKinds.includes(def.kind);
|
13
|
+
}
|
14
|
+
function getQueryTypeDef(definitions) {
|
15
|
+
var _a;
|
16
|
+
const schemaDef = definitions.find(def => def.kind === Kind.SCHEMA_DEFINITION);
|
17
|
+
const typeName = schemaDef
|
18
|
+
? (_a = schemaDef.operationTypes.find(({ operation }) => operation === 'query')) === null || _a === void 0 ? void 0 : _a.type.name.value
|
19
|
+
: 'Query';
|
20
|
+
return definitions.find(def => def.kind === Kind.OBJECT_TYPE_DEFINITION && def.name.value === typeName);
|
21
|
+
}
|
22
|
+
// Federation services are actually fairly complex,
|
23
|
+
// as the `buildFederatedSchema` helper does a fair amount
|
24
|
+
// of hidden work to setup the Federation schema specification:
|
25
|
+
// https://www.apollographql.com/docs/federation/federation-spec/#federation-schema-specification
|
26
|
+
export function federationToStitchingSDL(federationSDL, stitchingConfig = stitchingDirectives()) {
|
27
|
+
const doc = parse(federationSDL);
|
28
|
+
const entityTypes = [];
|
29
|
+
const baseTypeNames = doc.definitions.reduce((memo, typeDef) => {
|
30
|
+
if (!extensionKind.test(typeDef.kind) && 'name' in typeDef && typeDef.name) {
|
31
|
+
memo[typeDef.name.value] = true;
|
32
|
+
}
|
33
|
+
return memo;
|
34
|
+
}, {});
|
35
|
+
doc.definitions.forEach(typeDef => {
|
36
|
+
var _a, _b, _c;
|
37
|
+
// Un-extend all types (remove "extends" keywords)...
|
38
|
+
// extended types are invalid GraphQL without a local base type to extend from.
|
39
|
+
// Stitching merges flat types in lieu of hierarchical extensions.
|
40
|
+
if (extensionKind.test(typeDef.kind) && 'name' in typeDef && typeDef.name && !baseTypeNames[typeDef.name.value]) {
|
41
|
+
typeDef.kind = typeDef.kind.replace(extensionKind, 'Definition');
|
42
|
+
}
|
43
|
+
if (!isEntityKind(typeDef))
|
44
|
+
return;
|
45
|
+
// Find object definitions with "@key" directives;
|
46
|
+
// these are federated entities that get turned into merged types.
|
47
|
+
const keyDirs = [];
|
48
|
+
const otherDirs = [];
|
49
|
+
(_a = typeDef.directives) === null || _a === void 0 ? void 0 : _a.forEach(dir => {
|
50
|
+
if (dir.name.value === 'key') {
|
51
|
+
keyDirs.push(dir);
|
52
|
+
}
|
53
|
+
else {
|
54
|
+
otherDirs.push(dir);
|
55
|
+
}
|
56
|
+
});
|
57
|
+
if (!keyDirs.length)
|
58
|
+
return;
|
59
|
+
// Setup stitching MergedTypeConfig for all federated entities:
|
60
|
+
const selectionSet = `{ ${keyDirs.map((dir) => dir.arguments[0].value.value).join(' ')} }`;
|
61
|
+
const keyFields = parse(selectionSet).definitions[0].selectionSet.selections.map((sel) => sel.name.value);
|
62
|
+
const keyDir = keyDirs[0];
|
63
|
+
keyDir.name.value = stitchingConfig.keyDirective.name;
|
64
|
+
keyDir.arguments[0].name.value = 'selectionSet';
|
65
|
+
keyDir.arguments[0].value.value = selectionSet;
|
66
|
+
typeDef.directives = [keyDir, ...otherDirs];
|
67
|
+
// Remove non-key "@external" fields from the type...
|
68
|
+
// the stitching query planner expects services to only publish their own fields.
|
69
|
+
// This makes "@provides" moot because the query planner can automate the logic.
|
70
|
+
typeDef.fields = (_b = typeDef.fields) === null || _b === void 0 ? void 0 : _b.filter(fieldDef => {
|
71
|
+
var _a;
|
72
|
+
return (keyFields.includes(fieldDef.name.value) || !((_a = fieldDef.directives) === null || _a === void 0 ? void 0 : _a.find(dir => dir.name.value === 'external')));
|
73
|
+
});
|
74
|
+
// Discard remaining "@external" directives and any "@provides" directives
|
75
|
+
(_c = typeDef.fields) === null || _c === void 0 ? void 0 : _c.forEach((fieldDef) => {
|
76
|
+
fieldDef.directives = fieldDef.directives.filter((dir) => !/^(external|provides)$/.test(dir.name.value));
|
77
|
+
fieldDef.directives.forEach((dir) => {
|
78
|
+
if (dir.name.value === 'requires') {
|
79
|
+
dir.name.value = stitchingConfig.computedDirective.name;
|
80
|
+
dir.arguments[0].name.value = 'selectionSet';
|
81
|
+
dir.arguments[0].value.value = `{ ${dir.arguments[0].value.value} }`;
|
82
|
+
}
|
83
|
+
});
|
84
|
+
});
|
85
|
+
if (typeDef.kind === Kind.OBJECT_TYPE_DEFINITION || typeDef.kind === Kind.OBJECT_TYPE_EXTENSION) {
|
86
|
+
entityTypes.push(typeDef.name.value);
|
87
|
+
}
|
88
|
+
});
|
89
|
+
// Federation service SDLs are incomplete because they omit the federation spec itself...
|
90
|
+
// (https://www.apollographql.com/docs/federation/federation-spec/#federation-schema-specification)
|
91
|
+
// To make federation SDLs into valid and parsable GraphQL schemas,
|
92
|
+
// we must fill in the missing details from the specification.
|
93
|
+
if (entityTypes.length) {
|
94
|
+
const queryDef = getQueryTypeDef(doc.definitions);
|
95
|
+
const entitiesSchema = parse(/* GraphQL */ `
|
96
|
+
scalar _Any
|
97
|
+
union _Entity = ${entityTypes.filter((v, i, a) => a.indexOf(v) === i).join(' | ')}
|
98
|
+
type Query { _entities(representations: [_Any!]!): [_Entity]! @${stitchingConfig.mergeDirective.name} }
|
99
|
+
`).definitions;
|
100
|
+
doc.definitions.push(entitiesSchema[0]);
|
101
|
+
doc.definitions.push(entitiesSchema[1]);
|
102
|
+
if (queryDef) {
|
103
|
+
queryDef.fields.push(entitiesSchema[2].fields[0]);
|
104
|
+
}
|
105
|
+
else {
|
106
|
+
doc.definitions.push(entitiesSchema[2]);
|
107
|
+
}
|
108
|
+
}
|
109
|
+
return [stitchingConfig.stitchingDirectivesTypeDefs, print(doc)].join('\n');
|
110
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { TypeNameMetaFieldDef } from 'graphql';
|
2
|
+
import { pathsFromSelectionSet } from './pathsFromSelectionSet.js';
|
3
|
+
export function getSourcePaths(mappingInstructions, selectionSet) {
|
4
|
+
const sourcePaths = [];
|
5
|
+
for (const mappingInstruction of mappingInstructions) {
|
6
|
+
const { sourcePath } = mappingInstruction;
|
7
|
+
if (sourcePath.length) {
|
8
|
+
sourcePaths.push(sourcePath);
|
9
|
+
continue;
|
10
|
+
}
|
11
|
+
if (selectionSet == null) {
|
12
|
+
continue;
|
13
|
+
}
|
14
|
+
const paths = pathsFromSelectionSet(selectionSet);
|
15
|
+
for (const path of paths) {
|
16
|
+
sourcePaths.push(path);
|
17
|
+
}
|
18
|
+
sourcePaths.push([TypeNameMetaFieldDef.name]);
|
19
|
+
}
|
20
|
+
return sourcePaths;
|
21
|
+
}
|
package/esm/index.js
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
import { parseValue, valueFromASTUntyped } from 'graphql';
|
2
|
+
import { extractVariables } from './extractVariables.js';
|
3
|
+
import { EXPANSION_PREFIX, KEY_DELIMITER, preparseMergeArgsExpr } from './preparseMergeArgsExpr.js';
|
4
|
+
import { propertyTreeFromPaths } from './properties.js';
|
5
|
+
import { getSourcePaths } from './getSourcePaths.js';
|
6
|
+
export function parseMergeArgsExpr(mergeArgsExpr, selectionSet) {
|
7
|
+
const { mergeArgsExpr: newMergeArgsExpr, expansionExpressions } = preparseMergeArgsExpr(mergeArgsExpr);
|
8
|
+
const inputValue = parseValue(`{ ${newMergeArgsExpr} }`, { noLocation: true });
|
9
|
+
const { inputValue: newInputValue, variablePaths } = extractVariables(inputValue);
|
10
|
+
if (!Object.keys(expansionExpressions).length) {
|
11
|
+
if (!Object.keys(variablePaths).length) {
|
12
|
+
throw new Error('Merge arguments must declare a key.');
|
13
|
+
}
|
14
|
+
const mappingInstructions = getMappingInstructions(variablePaths);
|
15
|
+
const usedProperties = propertyTreeFromPaths(getSourcePaths(mappingInstructions, selectionSet));
|
16
|
+
return { args: valueFromASTUntyped(newInputValue), usedProperties, mappingInstructions };
|
17
|
+
}
|
18
|
+
const expansionRegEx = new RegExp(`^${EXPANSION_PREFIX}[0-9]+$`);
|
19
|
+
for (const variableName in variablePaths) {
|
20
|
+
if (!variableName.match(expansionRegEx)) {
|
21
|
+
throw new Error('Expansions cannot be mixed with single key declarations.');
|
22
|
+
}
|
23
|
+
}
|
24
|
+
const expansions = [];
|
25
|
+
const sourcePaths = [];
|
26
|
+
for (const variableName in expansionExpressions) {
|
27
|
+
const str = expansionExpressions[variableName];
|
28
|
+
const valuePath = variablePaths[variableName];
|
29
|
+
const { inputValue: expansionInputValue, variablePaths: expansionVariablePaths } = extractVariables(parseValue(`${str}`, { noLocation: true }));
|
30
|
+
if (!Object.keys(expansionVariablePaths).length) {
|
31
|
+
throw new Error('Merge arguments must declare a key.');
|
32
|
+
}
|
33
|
+
const mappingInstructions = getMappingInstructions(expansionVariablePaths);
|
34
|
+
const value = valueFromASTUntyped(expansionInputValue);
|
35
|
+
sourcePaths.push(...getSourcePaths(mappingInstructions, selectionSet));
|
36
|
+
assertNotWithinList(valuePath);
|
37
|
+
expansions.push({
|
38
|
+
valuePath,
|
39
|
+
value,
|
40
|
+
mappingInstructions,
|
41
|
+
});
|
42
|
+
}
|
43
|
+
const usedProperties = propertyTreeFromPaths(sourcePaths);
|
44
|
+
return { args: valueFromASTUntyped(newInputValue), usedProperties, expansions };
|
45
|
+
}
|
46
|
+
function getMappingInstructions(variablePaths) {
|
47
|
+
const mappingInstructions = [];
|
48
|
+
for (const keyPath in variablePaths) {
|
49
|
+
const valuePath = variablePaths[keyPath];
|
50
|
+
const splitKeyPath = keyPath.split(KEY_DELIMITER).slice(1);
|
51
|
+
assertNotWithinList(valuePath);
|
52
|
+
mappingInstructions.push({
|
53
|
+
destinationPath: valuePath,
|
54
|
+
sourcePath: splitKeyPath,
|
55
|
+
});
|
56
|
+
}
|
57
|
+
return mappingInstructions;
|
58
|
+
}
|
59
|
+
function assertNotWithinList(path) {
|
60
|
+
for (const pathSegment of path) {
|
61
|
+
if (typeof pathSegment === 'number') {
|
62
|
+
throw new Error('Insertions cannot be made into a list.');
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { Kind } from 'graphql';
|
2
|
+
export function pathsFromSelectionSet(selectionSet, path = []) {
|
3
|
+
var _a;
|
4
|
+
const paths = [];
|
5
|
+
for (const selection of selectionSet.selections) {
|
6
|
+
const additions = (_a = pathsFromSelection(selection, path)) !== null && _a !== void 0 ? _a : [];
|
7
|
+
for (const addition of additions) {
|
8
|
+
paths.push(addition);
|
9
|
+
}
|
10
|
+
}
|
11
|
+
return paths;
|
12
|
+
}
|
13
|
+
function pathsFromSelection(selection, path) {
|
14
|
+
var _a, _b;
|
15
|
+
if (selection.kind === Kind.FIELD) {
|
16
|
+
const responseKey = (_b = (_a = selection.alias) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : selection.name.value;
|
17
|
+
if (selection.selectionSet) {
|
18
|
+
return pathsFromSelectionSet(selection.selectionSet, path.concat([responseKey]));
|
19
|
+
}
|
20
|
+
else {
|
21
|
+
return [path.concat([responseKey])];
|
22
|
+
}
|
23
|
+
}
|
24
|
+
else if (selection.kind === Kind.INLINE_FRAGMENT) {
|
25
|
+
return pathsFromSelectionSet(selection.selectionSet, path);
|
26
|
+
}
|
27
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
export const KEY_DELIMITER = '__dot__';
|
2
|
+
export const EXPANSION_PREFIX = '__exp';
|
3
|
+
export function preparseMergeArgsExpr(mergeArgsExpr) {
|
4
|
+
const variableRegex = /\$[_A-Za-z][_A-Za-z0-9.]*/g;
|
5
|
+
const dotRegex = /\./g;
|
6
|
+
mergeArgsExpr = mergeArgsExpr.replace(variableRegex, variable => variable.replace(dotRegex, KEY_DELIMITER));
|
7
|
+
const segments = mergeArgsExpr.split('[[');
|
8
|
+
const expansionExpressions = Object.create(null);
|
9
|
+
if (segments.length === 1) {
|
10
|
+
return { mergeArgsExpr, expansionExpressions };
|
11
|
+
}
|
12
|
+
let finalSegments = [segments[0]];
|
13
|
+
for (let i = 1; i < segments.length; i++) {
|
14
|
+
const additionalSegments = segments[i].split(']]');
|
15
|
+
if (additionalSegments.length !== 2) {
|
16
|
+
throw new Error(`Each opening "[[" must be matched by a closing "]]" without nesting.`);
|
17
|
+
}
|
18
|
+
finalSegments = finalSegments.concat(additionalSegments);
|
19
|
+
}
|
20
|
+
let finalMergeArgsExpr = finalSegments[0];
|
21
|
+
for (let i = 1; i < finalSegments.length - 1; i += 2) {
|
22
|
+
const variableName = `${EXPANSION_PREFIX}${(i - 1) / 2 + 1}`;
|
23
|
+
expansionExpressions[variableName] = finalSegments[i];
|
24
|
+
finalMergeArgsExpr += `\$${variableName}${finalSegments[i + 1]}`;
|
25
|
+
}
|
26
|
+
return { mergeArgsExpr: finalMergeArgsExpr, expansionExpressions };
|
27
|
+
}
|
@@ -0,0 +1,63 @@
|
|
1
|
+
export function addProperty(object, path, value) {
|
2
|
+
const initialSegment = path[0];
|
3
|
+
if (path.length === 1) {
|
4
|
+
object[initialSegment] = value;
|
5
|
+
return;
|
6
|
+
}
|
7
|
+
let field = object[initialSegment];
|
8
|
+
if (field != null) {
|
9
|
+
addProperty(field, path.slice(1), value);
|
10
|
+
return;
|
11
|
+
}
|
12
|
+
if (typeof path[1] === 'string') {
|
13
|
+
field = Object.create(null);
|
14
|
+
}
|
15
|
+
else {
|
16
|
+
field = [];
|
17
|
+
}
|
18
|
+
addProperty(field, path.slice(1), value);
|
19
|
+
object[initialSegment] = field;
|
20
|
+
}
|
21
|
+
export function getProperty(object, path) {
|
22
|
+
if (!path.length || object == null) {
|
23
|
+
return object;
|
24
|
+
}
|
25
|
+
const newPath = path.slice();
|
26
|
+
const key = newPath.shift();
|
27
|
+
if (key == null) {
|
28
|
+
return;
|
29
|
+
}
|
30
|
+
const prop = object[key];
|
31
|
+
return getProperty(prop, newPath);
|
32
|
+
}
|
33
|
+
export function getProperties(object, propertyTree) {
|
34
|
+
if (object == null) {
|
35
|
+
return object;
|
36
|
+
}
|
37
|
+
const newObject = Object.create(null);
|
38
|
+
for (const key in propertyTree) {
|
39
|
+
const subKey = propertyTree[key];
|
40
|
+
if (subKey == null) {
|
41
|
+
newObject[key] = object[key];
|
42
|
+
continue;
|
43
|
+
}
|
44
|
+
const prop = object[key];
|
45
|
+
newObject[key] = deepMap(prop, function deepMapFn(item) {
|
46
|
+
return getProperties(item, subKey);
|
47
|
+
});
|
48
|
+
}
|
49
|
+
return newObject;
|
50
|
+
}
|
51
|
+
export function propertyTreeFromPaths(paths) {
|
52
|
+
const propertyTree = Object.create(null);
|
53
|
+
for (const path of paths) {
|
54
|
+
addProperty(propertyTree, path, null);
|
55
|
+
}
|
56
|
+
return propertyTree;
|
57
|
+
}
|
58
|
+
function deepMap(arrayOrItem, fn) {
|
59
|
+
if (Array.isArray(arrayOrItem)) {
|
60
|
+
return arrayOrItem.map(nestedArrayOrItem => deepMap(nestedArrayOrItem, fn));
|
61
|
+
}
|
62
|
+
return fn(arrayOrItem);
|
63
|
+
}
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import { GraphQLDirective, GraphQLList, GraphQLNonNull, GraphQLString } from 'graphql';
|
2
|
+
import { defaultStitchingDirectiveOptions } from './defaultStitchingDirectiveOptions.js';
|
3
|
+
import { stitchingDirectivesValidator } from './stitchingDirectivesValidator.js';
|
4
|
+
import { stitchingDirectivesTransformer } from './stitchingDirectivesTransformer.js';
|
5
|
+
export function stitchingDirectives(options = {}) {
|
6
|
+
const finalOptions = {
|
7
|
+
...defaultStitchingDirectiveOptions,
|
8
|
+
...options,
|
9
|
+
};
|
10
|
+
const { keyDirectiveName, computedDirectiveName, mergeDirectiveName, canonicalDirectiveName } = finalOptions;
|
11
|
+
const keyDirectiveTypeDefs = /* GraphQL */ `directive @${keyDirectiveName}(selectionSet: String!) on OBJECT`;
|
12
|
+
const computedDirectiveTypeDefs = /* GraphQL */ `directive @${computedDirectiveName}(selectionSet: String!) on FIELD_DEFINITION`;
|
13
|
+
const mergeDirectiveTypeDefs = /* GraphQL */ `directive @${mergeDirectiveName}(argsExpr: String, keyArg: String, keyField: String, key: [String!], additionalArgs: String) on FIELD_DEFINITION`;
|
14
|
+
const canonicalDirectiveTypeDefs = /* GraphQL */ `directive @${canonicalDirectiveName} on OBJECT | INTERFACE | INPUT_OBJECT | UNION | ENUM | SCALAR | FIELD_DEFINITION | INPUT_FIELD_DEFINITION`;
|
15
|
+
const keyDirective = new GraphQLDirective({
|
16
|
+
name: keyDirectiveName,
|
17
|
+
locations: ['OBJECT'],
|
18
|
+
args: {
|
19
|
+
selectionSet: { type: new GraphQLNonNull(GraphQLString) },
|
20
|
+
},
|
21
|
+
});
|
22
|
+
const computedDirective = new GraphQLDirective({
|
23
|
+
name: computedDirectiveName,
|
24
|
+
locations: ['FIELD_DEFINITION'],
|
25
|
+
args: {
|
26
|
+
selectionSet: { type: new GraphQLNonNull(GraphQLString) },
|
27
|
+
},
|
28
|
+
});
|
29
|
+
const mergeDirective = new GraphQLDirective({
|
30
|
+
name: mergeDirectiveName,
|
31
|
+
locations: ['FIELD_DEFINITION'],
|
32
|
+
args: {
|
33
|
+
argsExpr: { type: GraphQLString },
|
34
|
+
keyArg: { type: GraphQLString },
|
35
|
+
keyField: { type: GraphQLString },
|
36
|
+
key: { type: new GraphQLList(new GraphQLNonNull(GraphQLString)) },
|
37
|
+
additionalArgs: { type: GraphQLString },
|
38
|
+
},
|
39
|
+
});
|
40
|
+
const canonicalDirective = new GraphQLDirective({
|
41
|
+
name: canonicalDirectiveName,
|
42
|
+
locations: [
|
43
|
+
'OBJECT',
|
44
|
+
'INTERFACE',
|
45
|
+
'INPUT_OBJECT',
|
46
|
+
'UNION',
|
47
|
+
'ENUM',
|
48
|
+
'SCALAR',
|
49
|
+
'FIELD_DEFINITION',
|
50
|
+
'INPUT_FIELD_DEFINITION',
|
51
|
+
],
|
52
|
+
});
|
53
|
+
const allStitchingDirectivesTypeDefs = [
|
54
|
+
keyDirectiveTypeDefs,
|
55
|
+
computedDirectiveTypeDefs,
|
56
|
+
mergeDirectiveTypeDefs,
|
57
|
+
canonicalDirectiveTypeDefs,
|
58
|
+
].join('\n');
|
59
|
+
return {
|
60
|
+
keyDirectiveTypeDefs,
|
61
|
+
computedDirectiveTypeDefs,
|
62
|
+
mergeDirectiveTypeDefs,
|
63
|
+
canonicalDirectiveTypeDefs,
|
64
|
+
stitchingDirectivesTypeDefs: allStitchingDirectivesTypeDefs,
|
65
|
+
allStitchingDirectivesTypeDefs,
|
66
|
+
keyDirective,
|
67
|
+
computedDirective,
|
68
|
+
mergeDirective,
|
69
|
+
canonicalDirective,
|
70
|
+
allStitchingDirectives: [keyDirective, computedDirective, mergeDirective, canonicalDirective],
|
71
|
+
stitchingDirectivesValidator: stitchingDirectivesValidator(finalOptions),
|
72
|
+
stitchingDirectivesTransformer: stitchingDirectivesTransformer(finalOptions),
|
73
|
+
};
|
74
|
+
}
|