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