@graphql-mesh/transform-federation 1.0.0-alpha-3fc47d119.0 → 1.0.0-alpha-20230420181317-a95037648

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cjs/index.js ADDED
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const dset_1 = require("dset");
4
+ const graphql_1 = require("graphql");
5
+ const types_js_1 = require("@apollo/subgraph/dist/types.js");
6
+ const string_interpolation_1 = require("@graphql-mesh/string-interpolation");
7
+ const utils_1 = require("@graphql-mesh/utils");
8
+ const utils_2 = require("@graphql-tools/utils");
9
+ const federationDirectives = [
10
+ 'link',
11
+ 'key',
12
+ 'interfaceObject',
13
+ 'extends',
14
+ 'shareable',
15
+ 'inaccessible',
16
+ 'override',
17
+ 'external',
18
+ 'provides',
19
+ 'requires',
20
+ 'tag',
21
+ 'composeDirective',
22
+ ];
23
+ class FederationTransform {
24
+ constructor({ apiName, baseDir, config, importFn, }) {
25
+ this.noWrap = true;
26
+ this.apiName = apiName;
27
+ this.config = config;
28
+ this.baseDir = baseDir;
29
+ this.importFn = importFn;
30
+ }
31
+ transformSchema(schema, rawSource) {
32
+ var _a, _b, _c, _d, _e, _f, _g;
33
+ rawSource.merge = {};
34
+ if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.types) {
35
+ const queryType = schema.getQueryType();
36
+ const queryTypeFields = queryType.getFields();
37
+ for (const type of this.config.types) {
38
+ rawSource.merge[type.name] = {};
39
+ const typeObj = schema.getType(type.name);
40
+ typeObj.extensions = typeObj.extensions || {};
41
+ const typeDirectivesObj = (typeObj.extensions.directives =
42
+ typeObj.extensions.directives || {});
43
+ if ((_b = type.config) === null || _b === void 0 ? void 0 : _b.key) {
44
+ typeDirectivesObj.key = type.config.key;
45
+ }
46
+ if ((_c = type.config) === null || _c === void 0 ? void 0 : _c.shareable) {
47
+ typeDirectivesObj.shareable = type.config.shareable;
48
+ }
49
+ if ((_d = type.config) === null || _d === void 0 ? void 0 : _d.extends) {
50
+ typeDirectivesObj.extends = type.config.extends;
51
+ }
52
+ const typeFieldObjs = typeObj.getFields();
53
+ if ((_e = type.config) === null || _e === void 0 ? void 0 : _e.fields) {
54
+ for (const field of type.config.fields) {
55
+ const typeField = typeFieldObjs[field.name];
56
+ if (typeField) {
57
+ typeField.extensions = typeField.extensions || {};
58
+ const directivesObj = (typeField.extensions.directives =
59
+ typeField.extensions.directives || {});
60
+ Object.assign(directivesObj, field.config);
61
+ }
62
+ rawSource.merge[type.name].fields = rawSource.merge[type.name].fields || {};
63
+ rawSource.merge[type.name].fields[field.name] =
64
+ rawSource.merge[type.name].fields[field.name] || {};
65
+ if (field.config.requires) {
66
+ rawSource.merge[type.name].fields[field.name].computed = true;
67
+ rawSource.merge[type.name].fields[field.name].selectionSet = `{ ${field.config.requires} }`;
68
+ }
69
+ }
70
+ }
71
+ // If a field is a key field, it should be GraphQLID
72
+ if ((_f = type.config) === null || _f === void 0 ? void 0 : _f.key) {
73
+ let selectionSetContent = '';
74
+ for (const keyField of type.config.key) {
75
+ selectionSetContent += '\n';
76
+ selectionSetContent += keyField.fields || '';
77
+ }
78
+ if (selectionSetContent) {
79
+ rawSource.merge[type.name].selectionSet = `{ ${selectionSetContent} }`;
80
+ }
81
+ }
82
+ let resolveReference;
83
+ if ((_g = type.config) === null || _g === void 0 ? void 0 : _g.resolveReference) {
84
+ const resolveReferenceConfig = type.config.resolveReference;
85
+ if (typeof resolveReferenceConfig === 'string') {
86
+ const fn$ = (0, utils_1.loadFromModuleExportExpression)(resolveReferenceConfig, {
87
+ cwd: this.baseDir,
88
+ defaultExportName: 'default',
89
+ importFn: this.importFn,
90
+ });
91
+ resolveReference = (...args) => fn$.then(fn => fn(...args));
92
+ }
93
+ else if (typeof resolveReferenceConfig === 'function') {
94
+ resolveReference = resolveReferenceConfig;
95
+ }
96
+ else {
97
+ const queryField = queryTypeFields[resolveReferenceConfig.queryFieldName];
98
+ resolveReference = async (root, context, info) => {
99
+ const args = {};
100
+ for (const argName in resolveReferenceConfig.args) {
101
+ const argVal = string_interpolation_1.stringInterpolator.parse(resolveReferenceConfig.args[argName], {
102
+ root,
103
+ args,
104
+ context,
105
+ info,
106
+ env: process.env,
107
+ });
108
+ if (argVal) {
109
+ (0, dset_1.dset)(args, argName, argVal);
110
+ }
111
+ }
112
+ const result = await context[this.apiName].Query[queryField.name]({
113
+ root,
114
+ args,
115
+ context,
116
+ info,
117
+ });
118
+ return {
119
+ ...root,
120
+ ...result,
121
+ };
122
+ };
123
+ }
124
+ rawSource.merge[type.name].resolve = resolveReference;
125
+ }
126
+ }
127
+ }
128
+ const entityTypes = [];
129
+ for (const typeName in rawSource.merge || {}) {
130
+ const type = schema.getType(typeName);
131
+ if ((0, graphql_1.isObjectType)(type)) {
132
+ entityTypes.push(type);
133
+ }
134
+ (0, dset_1.dset)(type, 'extensions.apollo.subgraph.resolveReference', rawSource.merge[typeName].resolve);
135
+ }
136
+ const schemaWithFederationQueryType = (0, utils_2.mapSchema)(schema, {
137
+ [utils_2.MapperKind.QUERY]: type => {
138
+ const config = type.toConfig();
139
+ return new graphql_1.GraphQLObjectType({
140
+ ...config,
141
+ fields: {
142
+ ...config.fields,
143
+ _entities: types_js_1.entitiesField,
144
+ _service: {
145
+ ...types_js_1.serviceField,
146
+ resolve: (root, args, context, info) => ({
147
+ sdl: (0, utils_2.printSchemaWithDirectives)(info.schema),
148
+ }),
149
+ },
150
+ },
151
+ });
152
+ },
153
+ });
154
+ const schemaWithUnionType = (0, utils_2.mapSchema)(schemaWithFederationQueryType, {
155
+ [utils_2.MapperKind.UNION_TYPE]: type => {
156
+ if (type.name === types_js_1.EntityType.name) {
157
+ return new graphql_1.GraphQLUnionType({
158
+ ...types_js_1.EntityType.toConfig(),
159
+ types: entityTypes,
160
+ });
161
+ }
162
+ return type;
163
+ },
164
+ });
165
+ schemaWithUnionType.extensions = schemaWithUnionType.extensions || {};
166
+ const directivesObj = (schemaWithUnionType.extensions.directives =
167
+ schemaWithUnionType.extensions.directives || {});
168
+ const existingDirectives = schemaWithUnionType.getDirectives();
169
+ const filteredDirectives = existingDirectives.filter(directive => federationDirectives.includes(directive.name));
170
+ directivesObj.link = {
171
+ url: 'https://specs.apollo.dev/federation/' + (this.config.version || 'v2.0'),
172
+ import: filteredDirectives
173
+ .filter(({ name }) => name !== 'link')
174
+ .map(dirName => `@${dirName.name}`),
175
+ };
176
+ if (existingDirectives.length === filteredDirectives.length) {
177
+ return schemaWithUnionType;
178
+ }
179
+ return (0, utils_2.mapSchema)(schemaWithUnionType, {
180
+ [utils_2.MapperKind.DIRECTIVE]: directive => {
181
+ if (federationDirectives.includes(directive.name)) {
182
+ return directive;
183
+ }
184
+ return null;
185
+ },
186
+ [utils_2.MapperKind.OBJECT_TYPE]: type => {
187
+ var _a, _b;
188
+ return new graphql_1.GraphQLObjectType({
189
+ ...type.toConfig(),
190
+ astNode: type.astNode && {
191
+ ...type.astNode,
192
+ directives: (_a = type.astNode.directives) === null || _a === void 0 ? void 0 : _a.filter(directive => federationDirectives.includes(directive.name.value)),
193
+ },
194
+ extensions: {
195
+ ...type.extensions,
196
+ directives: Object.fromEntries(Object.entries(((_b = type.extensions) === null || _b === void 0 ? void 0 : _b.directives) || {}).filter(([key]) => federationDirectives.includes(key))),
197
+ },
198
+ });
199
+ },
200
+ [utils_2.MapperKind.INTERFACE_TYPE]: type => {
201
+ var _a, _b;
202
+ return new graphql_1.GraphQLInterfaceType({
203
+ ...type.toConfig(),
204
+ astNode: type.astNode && {
205
+ ...type.astNode,
206
+ directives: (_a = type.astNode.directives) === null || _a === void 0 ? void 0 : _a.filter(directive => federationDirectives.includes(directive.name.value)),
207
+ },
208
+ extensions: {
209
+ ...type.extensions,
210
+ directives: Object.fromEntries(Object.entries(((_b = type.extensions) === null || _b === void 0 ? void 0 : _b.directives) || {}).filter(([key]) => federationDirectives.includes(key))),
211
+ },
212
+ });
213
+ },
214
+ [utils_2.MapperKind.COMPOSITE_FIELD]: fieldConfig => {
215
+ var _a, _b;
216
+ return {
217
+ ...fieldConfig,
218
+ astNode: fieldConfig.astNode && {
219
+ ...fieldConfig.astNode,
220
+ directives: (_a = fieldConfig.astNode.directives) === null || _a === void 0 ? void 0 : _a.filter(directive => federationDirectives.includes(directive.name.value)),
221
+ },
222
+ extensions: {
223
+ ...fieldConfig.extensions,
224
+ directives: Object.fromEntries(Object.entries(((_b = fieldConfig.extensions) === null || _b === void 0 ? void 0 : _b.directives) || {}).filter(([key]) => federationDirectives.includes(key))),
225
+ },
226
+ };
227
+ },
228
+ });
229
+ }
230
+ }
231
+ exports.default = FederationTransform;
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
package/esm/index.js ADDED
@@ -0,0 +1,228 @@
1
+ import { dset } from 'dset';
2
+ import { GraphQLInterfaceType, GraphQLObjectType, GraphQLUnionType, isObjectType, } from 'graphql';
3
+ import { entitiesField, EntityType, serviceField } from '@apollo/subgraph/dist/types.js';
4
+ import { stringInterpolator } from '@graphql-mesh/string-interpolation';
5
+ import { loadFromModuleExportExpression } from '@graphql-mesh/utils';
6
+ import { MapperKind, mapSchema, printSchemaWithDirectives } from '@graphql-tools/utils';
7
+ const federationDirectives = [
8
+ 'link',
9
+ 'key',
10
+ 'interfaceObject',
11
+ 'extends',
12
+ 'shareable',
13
+ 'inaccessible',
14
+ 'override',
15
+ 'external',
16
+ 'provides',
17
+ 'requires',
18
+ 'tag',
19
+ 'composeDirective',
20
+ ];
21
+ export default class FederationTransform {
22
+ constructor({ apiName, baseDir, config, importFn, }) {
23
+ this.noWrap = true;
24
+ this.apiName = apiName;
25
+ this.config = config;
26
+ this.baseDir = baseDir;
27
+ this.importFn = importFn;
28
+ }
29
+ transformSchema(schema, rawSource) {
30
+ var _a, _b, _c, _d, _e, _f, _g;
31
+ rawSource.merge = {};
32
+ if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.types) {
33
+ const queryType = schema.getQueryType();
34
+ const queryTypeFields = queryType.getFields();
35
+ for (const type of this.config.types) {
36
+ rawSource.merge[type.name] = {};
37
+ const typeObj = schema.getType(type.name);
38
+ typeObj.extensions = typeObj.extensions || {};
39
+ const typeDirectivesObj = (typeObj.extensions.directives =
40
+ typeObj.extensions.directives || {});
41
+ if ((_b = type.config) === null || _b === void 0 ? void 0 : _b.key) {
42
+ typeDirectivesObj.key = type.config.key;
43
+ }
44
+ if ((_c = type.config) === null || _c === void 0 ? void 0 : _c.shareable) {
45
+ typeDirectivesObj.shareable = type.config.shareable;
46
+ }
47
+ if ((_d = type.config) === null || _d === void 0 ? void 0 : _d.extends) {
48
+ typeDirectivesObj.extends = type.config.extends;
49
+ }
50
+ const typeFieldObjs = typeObj.getFields();
51
+ if ((_e = type.config) === null || _e === void 0 ? void 0 : _e.fields) {
52
+ for (const field of type.config.fields) {
53
+ const typeField = typeFieldObjs[field.name];
54
+ if (typeField) {
55
+ typeField.extensions = typeField.extensions || {};
56
+ const directivesObj = (typeField.extensions.directives =
57
+ typeField.extensions.directives || {});
58
+ Object.assign(directivesObj, field.config);
59
+ }
60
+ rawSource.merge[type.name].fields = rawSource.merge[type.name].fields || {};
61
+ rawSource.merge[type.name].fields[field.name] =
62
+ rawSource.merge[type.name].fields[field.name] || {};
63
+ if (field.config.requires) {
64
+ rawSource.merge[type.name].fields[field.name].computed = true;
65
+ rawSource.merge[type.name].fields[field.name].selectionSet = `{ ${field.config.requires} }`;
66
+ }
67
+ }
68
+ }
69
+ // If a field is a key field, it should be GraphQLID
70
+ if ((_f = type.config) === null || _f === void 0 ? void 0 : _f.key) {
71
+ let selectionSetContent = '';
72
+ for (const keyField of type.config.key) {
73
+ selectionSetContent += '\n';
74
+ selectionSetContent += keyField.fields || '';
75
+ }
76
+ if (selectionSetContent) {
77
+ rawSource.merge[type.name].selectionSet = `{ ${selectionSetContent} }`;
78
+ }
79
+ }
80
+ let resolveReference;
81
+ if ((_g = type.config) === null || _g === void 0 ? void 0 : _g.resolveReference) {
82
+ const resolveReferenceConfig = type.config.resolveReference;
83
+ if (typeof resolveReferenceConfig === 'string') {
84
+ const fn$ = loadFromModuleExportExpression(resolveReferenceConfig, {
85
+ cwd: this.baseDir,
86
+ defaultExportName: 'default',
87
+ importFn: this.importFn,
88
+ });
89
+ resolveReference = (...args) => fn$.then(fn => fn(...args));
90
+ }
91
+ else if (typeof resolveReferenceConfig === 'function') {
92
+ resolveReference = resolveReferenceConfig;
93
+ }
94
+ else {
95
+ const queryField = queryTypeFields[resolveReferenceConfig.queryFieldName];
96
+ resolveReference = async (root, context, info) => {
97
+ const args = {};
98
+ for (const argName in resolveReferenceConfig.args) {
99
+ const argVal = stringInterpolator.parse(resolveReferenceConfig.args[argName], {
100
+ root,
101
+ args,
102
+ context,
103
+ info,
104
+ env: process.env,
105
+ });
106
+ if (argVal) {
107
+ dset(args, argName, argVal);
108
+ }
109
+ }
110
+ const result = await context[this.apiName].Query[queryField.name]({
111
+ root,
112
+ args,
113
+ context,
114
+ info,
115
+ });
116
+ return {
117
+ ...root,
118
+ ...result,
119
+ };
120
+ };
121
+ }
122
+ rawSource.merge[type.name].resolve = resolveReference;
123
+ }
124
+ }
125
+ }
126
+ const entityTypes = [];
127
+ for (const typeName in rawSource.merge || {}) {
128
+ const type = schema.getType(typeName);
129
+ if (isObjectType(type)) {
130
+ entityTypes.push(type);
131
+ }
132
+ dset(type, 'extensions.apollo.subgraph.resolveReference', rawSource.merge[typeName].resolve);
133
+ }
134
+ const schemaWithFederationQueryType = mapSchema(schema, {
135
+ [MapperKind.QUERY]: type => {
136
+ const config = type.toConfig();
137
+ return new GraphQLObjectType({
138
+ ...config,
139
+ fields: {
140
+ ...config.fields,
141
+ _entities: entitiesField,
142
+ _service: {
143
+ ...serviceField,
144
+ resolve: (root, args, context, info) => ({
145
+ sdl: printSchemaWithDirectives(info.schema),
146
+ }),
147
+ },
148
+ },
149
+ });
150
+ },
151
+ });
152
+ const schemaWithUnionType = mapSchema(schemaWithFederationQueryType, {
153
+ [MapperKind.UNION_TYPE]: type => {
154
+ if (type.name === EntityType.name) {
155
+ return new GraphQLUnionType({
156
+ ...EntityType.toConfig(),
157
+ types: entityTypes,
158
+ });
159
+ }
160
+ return type;
161
+ },
162
+ });
163
+ schemaWithUnionType.extensions = schemaWithUnionType.extensions || {};
164
+ const directivesObj = (schemaWithUnionType.extensions.directives =
165
+ schemaWithUnionType.extensions.directives || {});
166
+ const existingDirectives = schemaWithUnionType.getDirectives();
167
+ const filteredDirectives = existingDirectives.filter(directive => federationDirectives.includes(directive.name));
168
+ directivesObj.link = {
169
+ url: 'https://specs.apollo.dev/federation/' + (this.config.version || 'v2.0'),
170
+ import: filteredDirectives
171
+ .filter(({ name }) => name !== 'link')
172
+ .map(dirName => `@${dirName.name}`),
173
+ };
174
+ if (existingDirectives.length === filteredDirectives.length) {
175
+ return schemaWithUnionType;
176
+ }
177
+ return mapSchema(schemaWithUnionType, {
178
+ [MapperKind.DIRECTIVE]: directive => {
179
+ if (federationDirectives.includes(directive.name)) {
180
+ return directive;
181
+ }
182
+ return null;
183
+ },
184
+ [MapperKind.OBJECT_TYPE]: type => {
185
+ var _a, _b;
186
+ return new GraphQLObjectType({
187
+ ...type.toConfig(),
188
+ astNode: type.astNode && {
189
+ ...type.astNode,
190
+ directives: (_a = type.astNode.directives) === null || _a === void 0 ? void 0 : _a.filter(directive => federationDirectives.includes(directive.name.value)),
191
+ },
192
+ extensions: {
193
+ ...type.extensions,
194
+ directives: Object.fromEntries(Object.entries(((_b = type.extensions) === null || _b === void 0 ? void 0 : _b.directives) || {}).filter(([key]) => federationDirectives.includes(key))),
195
+ },
196
+ });
197
+ },
198
+ [MapperKind.INTERFACE_TYPE]: type => {
199
+ var _a, _b;
200
+ return new GraphQLInterfaceType({
201
+ ...type.toConfig(),
202
+ astNode: type.astNode && {
203
+ ...type.astNode,
204
+ directives: (_a = type.astNode.directives) === null || _a === void 0 ? void 0 : _a.filter(directive => federationDirectives.includes(directive.name.value)),
205
+ },
206
+ extensions: {
207
+ ...type.extensions,
208
+ directives: Object.fromEntries(Object.entries(((_b = type.extensions) === null || _b === void 0 ? void 0 : _b.directives) || {}).filter(([key]) => federationDirectives.includes(key))),
209
+ },
210
+ });
211
+ },
212
+ [MapperKind.COMPOSITE_FIELD]: fieldConfig => {
213
+ var _a, _b;
214
+ return {
215
+ ...fieldConfig,
216
+ astNode: fieldConfig.astNode && {
217
+ ...fieldConfig.astNode,
218
+ directives: (_a = fieldConfig.astNode.directives) === null || _a === void 0 ? void 0 : _a.filter(directive => federationDirectives.includes(directive.name.value)),
219
+ },
220
+ extensions: {
221
+ ...fieldConfig.extensions,
222
+ directives: Object.fromEntries(Object.entries(((_b = fieldConfig.extensions) === null || _b === void 0 ? void 0 : _b.directives) || {}).filter(([key]) => federationDirectives.includes(key))),
223
+ },
224
+ };
225
+ },
226
+ });
227
+ }
228
+ }
package/package.json CHANGED
@@ -1,19 +1,21 @@
1
1
  {
2
2
  "name": "@graphql-mesh/transform-federation",
3
- "version": "1.0.0-alpha-3fc47d119.0",
3
+ "version": "1.0.0-alpha-20230420181317-a95037648",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
- "@graphql-mesh/types": "0.79.0-alpha-3fc47d119.0",
7
- "@graphql-mesh/utils": "1.0.0-alpha-3fc47d119.0",
8
- "graphql": "*"
6
+ "@graphql-mesh/types": "1.0.0-alpha-20230420181317-a95037648",
7
+ "@graphql-mesh/utils": "1.0.0-alpha-20230420181317-a95037648",
8
+ "@graphql-tools/utils": "^9.2.1",
9
+ "graphql": "*",
10
+ "tslib": "^2.4.0"
9
11
  },
10
12
  "dependencies": {
11
- "@apollo/subgraph": "2.0.5",
12
- "@graphql-tools/delegate": "8.8.0",
13
- "@graphql-tools/stitching-directives": "2.3.0",
14
- "@graphql-tools/utils": "8.8.0",
15
- "graphql-transform-federation": "2.2.0",
16
- "tslib": "^2.4.0"
13
+ "@apollo/subgraph": "2.4.1",
14
+ "@graphql-mesh/string-interpolation": "0.4.4",
15
+ "@graphql-tools/delegate": "9.0.32",
16
+ "@graphql-tools/stitching-directives": "2.3.34",
17
+ "dset": "3.1.2",
18
+ "graphql-transform-federation": "2.2.0"
17
19
  },
18
20
  "repository": {
19
21
  "type": "git",
@@ -21,21 +23,28 @@
21
23
  "directory": "packages/transforms/federation"
22
24
  },
23
25
  "license": "MIT",
24
- "main": "index.js",
25
- "module": "index.mjs",
26
- "typings": "index.d.ts",
26
+ "main": "cjs/index.js",
27
+ "module": "esm/index.js",
28
+ "typings": "typings/index.d.ts",
27
29
  "typescript": {
28
- "definition": "index.d.ts"
30
+ "definition": "typings/index.d.ts"
29
31
  },
32
+ "type": "module",
30
33
  "exports": {
31
34
  ".": {
32
- "require": "./index.js",
33
- "import": "./index.mjs"
34
- },
35
- "./*": {
36
- "require": "./*.js",
37
- "import": "./*.mjs"
35
+ "require": {
36
+ "types": "./typings/index.d.cts",
37
+ "default": "./cjs/index.js"
38
+ },
39
+ "import": {
40
+ "types": "./typings/index.d.ts",
41
+ "default": "./esm/index.js"
42
+ },
43
+ "default": {
44
+ "types": "./typings/index.d.ts",
45
+ "default": "./esm/index.js"
46
+ }
38
47
  },
39
48
  "./package.json": "./package.json"
40
49
  }
41
- }
50
+ }
@@ -0,0 +1,12 @@
1
+ import { GraphQLSchema } from 'graphql';
2
+ import { MeshTransform, MeshTransformOptions, YamlConfig } from '@graphql-mesh/types';
3
+ import { SubschemaConfig } from '@graphql-tools/delegate';
4
+ export default class FederationTransform implements MeshTransform {
5
+ private apiName;
6
+ private config;
7
+ private baseDir;
8
+ private importFn;
9
+ noWrap: boolean;
10
+ constructor({ apiName, baseDir, config, importFn, }: MeshTransformOptions<YamlConfig.Transform['federation']>);
11
+ transformSchema(schema: GraphQLSchema, rawSource: SubschemaConfig): GraphQLSchema;
12
+ }
@@ -1,11 +1,12 @@
1
1
  import { GraphQLSchema } from 'graphql';
2
- import { MeshTransform, YamlConfig, MeshTransformOptions } from '@graphql-mesh/types';
2
+ import { MeshTransform, MeshTransformOptions, YamlConfig } from '@graphql-mesh/types';
3
3
  import { SubschemaConfig } from '@graphql-tools/delegate';
4
4
  export default class FederationTransform implements MeshTransform {
5
5
  private apiName;
6
6
  private config;
7
7
  private baseDir;
8
8
  private importFn;
9
- constructor({ apiName, baseDir, config, importFn }: MeshTransformOptions<YamlConfig.Transform['federation']>);
9
+ noWrap: boolean;
10
+ constructor({ apiName, baseDir, config, importFn, }: MeshTransformOptions<YamlConfig.Transform['federation']>);
10
11
  transformSchema(schema: GraphQLSchema, rawSource: SubschemaConfig): GraphQLSchema;
11
12
  }
package/index.js DELETED
@@ -1,156 +0,0 @@
1
- 'use strict';
2
-
3
- const graphql = require('graphql');
4
- const utils = require('@graphql-mesh/utils');
5
- const transformSdl_js = require('graphql-transform-federation/dist/transform-sdl.js');
6
- const types_js = require('@apollo/subgraph/dist/types.js');
7
- const utils$1 = require('@graphql-tools/utils');
8
-
9
- class FederationTransform {
10
- constructor({ apiName, baseDir, config, importFn }) {
11
- this.apiName = apiName;
12
- this.config = config;
13
- this.baseDir = baseDir;
14
- this.importFn = importFn;
15
- }
16
- transformSchema(schema, rawSource) {
17
- var _a, _b, _c, _d;
18
- const federationConfig = {};
19
- rawSource.merge = {};
20
- if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.types) {
21
- const queryType = schema.getQueryType();
22
- const queryTypeFields = queryType.getFields();
23
- for (const type of this.config.types) {
24
- rawSource.merge[type.name] = {};
25
- const fields = {};
26
- if ((_b = type.config) === null || _b === void 0 ? void 0 : _b.fields) {
27
- for (const field of type.config.fields) {
28
- fields[field.name] = field.config;
29
- rawSource.merge[type.name].fields = rawSource.merge[type.name].fields || {};
30
- rawSource.merge[type.name].fields[field.name] = rawSource.merge[type.name].fields[field.name] || {};
31
- if (field.config.requires) {
32
- rawSource.merge[type.name].fields[field.name].computed = true;
33
- rawSource.merge[type.name].fields[field.name].selectionSet = `{ ${field.config.requires} }`;
34
- }
35
- }
36
- }
37
- // If a field is a key field, it should be GraphQLID
38
- if ((_c = type.config) === null || _c === void 0 ? void 0 : _c.keyFields) {
39
- rawSource.merge[type.name].selectionSet = `{ ${type.config.keyFields.join(' ')} }`;
40
- for (const fieldName of type.config.keyFields) {
41
- const objectType = schema.getType(type.name);
42
- if (objectType) {
43
- const existingType = objectType.getFields()[fieldName].type;
44
- objectType.getFields()[fieldName].type = graphql.isNonNullType(existingType)
45
- ? new graphql.GraphQLNonNull(graphql.GraphQLID)
46
- : graphql.GraphQLID;
47
- }
48
- }
49
- }
50
- let resolveReference;
51
- if ((_d = type.config) === null || _d === void 0 ? void 0 : _d.resolveReference) {
52
- const resolveReferenceConfig = type.config.resolveReference;
53
- if (typeof resolveReferenceConfig === 'string') {
54
- const fn$ = utils.loadFromModuleExportExpression(resolveReferenceConfig, {
55
- cwd: this.baseDir,
56
- defaultExportName: 'default',
57
- importFn: this.importFn,
58
- });
59
- resolveReference = (...args) => fn$.then(fn => fn(...args));
60
- }
61
- else if (typeof resolveReferenceConfig === 'function') {
62
- resolveReference = resolveReferenceConfig;
63
- }
64
- else {
65
- const queryField = queryTypeFields[resolveReferenceConfig.queryFieldName];
66
- const keyArg = resolveReferenceConfig.keyArg || queryField.args[0].name;
67
- const keyField = type.config.keyFields[0];
68
- const isBatch = graphql.isListType(queryField.args.find(arg => arg.name === keyArg));
69
- resolveReference = async (root, context, info) => {
70
- const result = await context[this.apiName].Query[queryField.name]({
71
- root,
72
- ...(isBatch
73
- ? {
74
- key: root[keyField],
75
- argsFromKeys: (keys) => ({
76
- [keyArg]: keys,
77
- }),
78
- }
79
- : {
80
- args: {
81
- [keyArg]: root[keyField],
82
- },
83
- }),
84
- context,
85
- info,
86
- });
87
- return {
88
- ...root,
89
- ...result,
90
- };
91
- };
92
- }
93
- rawSource.merge[type.name].resolve = resolveReference;
94
- }
95
- federationConfig[type.name] = {
96
- ...type.config,
97
- resolveReference,
98
- fields,
99
- };
100
- }
101
- }
102
- const entityTypes = Object.fromEntries(Object.entries(federationConfig)
103
- .filter(([, { keyFields }]) => keyFields === null || keyFields === void 0 ? void 0 : keyFields.length)
104
- .map(([objectName]) => {
105
- const type = schema.getType(objectName);
106
- if (!graphql.isObjectType(type)) {
107
- throw new Error(`Type "${objectName}" is not an object type and can't have a key directive`);
108
- }
109
- return [objectName, type];
110
- }));
111
- const hasEntities = !!Object.keys(entityTypes).length;
112
- const sdlWithFederationDirectives = transformSdl_js.addFederationAnnotations(utils$1.printSchemaWithDirectives(schema), federationConfig);
113
- const schemaWithFederationQueryType = utils$1.mapSchema(schema, {
114
- [utils$1.MapperKind.QUERY]: type => {
115
- const config = type.toConfig();
116
- return new graphql.GraphQLObjectType({
117
- ...config,
118
- fields: {
119
- ...config.fields,
120
- ...(hasEntities && {
121
- _entities: types_js.entitiesField,
122
- _service: {
123
- ...types_js.serviceField,
124
- resolve: () => ({ sdl: sdlWithFederationDirectives }),
125
- },
126
- }),
127
- },
128
- });
129
- },
130
- });
131
- const schemaWithUnionType = utils$1.mapSchema(schemaWithFederationQueryType, {
132
- [utils$1.MapperKind.UNION_TYPE]: type => {
133
- if (type.name === types_js.EntityType.name) {
134
- return new graphql.GraphQLUnionType({
135
- ...types_js.EntityType.toConfig(),
136
- types: Object.values(entityTypes),
137
- });
138
- }
139
- return type;
140
- },
141
- });
142
- // Not using transformSchema since it will remove resolveReference
143
- Object.entries(federationConfig).forEach(([objectName, currentFederationConfig]) => {
144
- if (currentFederationConfig.resolveReference) {
145
- const type = schemaWithUnionType.getType(objectName);
146
- if (!graphql.isObjectType(type)) {
147
- throw new Error(`Type "${objectName}" is not an object type and can't have a resolveReference function`);
148
- }
149
- type.resolveObject = currentFederationConfig.resolveReference;
150
- }
151
- });
152
- return schemaWithUnionType;
153
- }
154
- }
155
-
156
- module.exports = FederationTransform;
package/index.mjs DELETED
@@ -1,154 +0,0 @@
1
- import { isNonNullType, GraphQLNonNull, GraphQLID, isListType, isObjectType, GraphQLObjectType, GraphQLUnionType } from 'graphql';
2
- import { loadFromModuleExportExpression } from '@graphql-mesh/utils';
3
- import { addFederationAnnotations } from 'graphql-transform-federation/dist/transform-sdl.js';
4
- import { entitiesField, serviceField, EntityType } from '@apollo/subgraph/dist/types.js';
5
- import { printSchemaWithDirectives, mapSchema, MapperKind } from '@graphql-tools/utils';
6
-
7
- class FederationTransform {
8
- constructor({ apiName, baseDir, config, importFn }) {
9
- this.apiName = apiName;
10
- this.config = config;
11
- this.baseDir = baseDir;
12
- this.importFn = importFn;
13
- }
14
- transformSchema(schema, rawSource) {
15
- var _a, _b, _c, _d;
16
- const federationConfig = {};
17
- rawSource.merge = {};
18
- if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.types) {
19
- const queryType = schema.getQueryType();
20
- const queryTypeFields = queryType.getFields();
21
- for (const type of this.config.types) {
22
- rawSource.merge[type.name] = {};
23
- const fields = {};
24
- if ((_b = type.config) === null || _b === void 0 ? void 0 : _b.fields) {
25
- for (const field of type.config.fields) {
26
- fields[field.name] = field.config;
27
- rawSource.merge[type.name].fields = rawSource.merge[type.name].fields || {};
28
- rawSource.merge[type.name].fields[field.name] = rawSource.merge[type.name].fields[field.name] || {};
29
- if (field.config.requires) {
30
- rawSource.merge[type.name].fields[field.name].computed = true;
31
- rawSource.merge[type.name].fields[field.name].selectionSet = `{ ${field.config.requires} }`;
32
- }
33
- }
34
- }
35
- // If a field is a key field, it should be GraphQLID
36
- if ((_c = type.config) === null || _c === void 0 ? void 0 : _c.keyFields) {
37
- rawSource.merge[type.name].selectionSet = `{ ${type.config.keyFields.join(' ')} }`;
38
- for (const fieldName of type.config.keyFields) {
39
- const objectType = schema.getType(type.name);
40
- if (objectType) {
41
- const existingType = objectType.getFields()[fieldName].type;
42
- objectType.getFields()[fieldName].type = isNonNullType(existingType)
43
- ? new GraphQLNonNull(GraphQLID)
44
- : GraphQLID;
45
- }
46
- }
47
- }
48
- let resolveReference;
49
- if ((_d = type.config) === null || _d === void 0 ? void 0 : _d.resolveReference) {
50
- const resolveReferenceConfig = type.config.resolveReference;
51
- if (typeof resolveReferenceConfig === 'string') {
52
- const fn$ = loadFromModuleExportExpression(resolveReferenceConfig, {
53
- cwd: this.baseDir,
54
- defaultExportName: 'default',
55
- importFn: this.importFn,
56
- });
57
- resolveReference = (...args) => fn$.then(fn => fn(...args));
58
- }
59
- else if (typeof resolveReferenceConfig === 'function') {
60
- resolveReference = resolveReferenceConfig;
61
- }
62
- else {
63
- const queryField = queryTypeFields[resolveReferenceConfig.queryFieldName];
64
- const keyArg = resolveReferenceConfig.keyArg || queryField.args[0].name;
65
- const keyField = type.config.keyFields[0];
66
- const isBatch = isListType(queryField.args.find(arg => arg.name === keyArg));
67
- resolveReference = async (root, context, info) => {
68
- const result = await context[this.apiName].Query[queryField.name]({
69
- root,
70
- ...(isBatch
71
- ? {
72
- key: root[keyField],
73
- argsFromKeys: (keys) => ({
74
- [keyArg]: keys,
75
- }),
76
- }
77
- : {
78
- args: {
79
- [keyArg]: root[keyField],
80
- },
81
- }),
82
- context,
83
- info,
84
- });
85
- return {
86
- ...root,
87
- ...result,
88
- };
89
- };
90
- }
91
- rawSource.merge[type.name].resolve = resolveReference;
92
- }
93
- federationConfig[type.name] = {
94
- ...type.config,
95
- resolveReference,
96
- fields,
97
- };
98
- }
99
- }
100
- const entityTypes = Object.fromEntries(Object.entries(federationConfig)
101
- .filter(([, { keyFields }]) => keyFields === null || keyFields === void 0 ? void 0 : keyFields.length)
102
- .map(([objectName]) => {
103
- const type = schema.getType(objectName);
104
- if (!isObjectType(type)) {
105
- throw new Error(`Type "${objectName}" is not an object type and can't have a key directive`);
106
- }
107
- return [objectName, type];
108
- }));
109
- const hasEntities = !!Object.keys(entityTypes).length;
110
- const sdlWithFederationDirectives = addFederationAnnotations(printSchemaWithDirectives(schema), federationConfig);
111
- const schemaWithFederationQueryType = mapSchema(schema, {
112
- [MapperKind.QUERY]: type => {
113
- const config = type.toConfig();
114
- return new GraphQLObjectType({
115
- ...config,
116
- fields: {
117
- ...config.fields,
118
- ...(hasEntities && {
119
- _entities: entitiesField,
120
- _service: {
121
- ...serviceField,
122
- resolve: () => ({ sdl: sdlWithFederationDirectives }),
123
- },
124
- }),
125
- },
126
- });
127
- },
128
- });
129
- const schemaWithUnionType = mapSchema(schemaWithFederationQueryType, {
130
- [MapperKind.UNION_TYPE]: type => {
131
- if (type.name === EntityType.name) {
132
- return new GraphQLUnionType({
133
- ...EntityType.toConfig(),
134
- types: Object.values(entityTypes),
135
- });
136
- }
137
- return type;
138
- },
139
- });
140
- // Not using transformSchema since it will remove resolveReference
141
- Object.entries(federationConfig).forEach(([objectName, currentFederationConfig]) => {
142
- if (currentFederationConfig.resolveReference) {
143
- const type = schemaWithUnionType.getType(objectName);
144
- if (!isObjectType(type)) {
145
- throw new Error(`Type "${objectName}" is not an object type and can't have a resolveReference function`);
146
- }
147
- type.resolveObject = currentFederationConfig.resolveReference;
148
- }
149
- });
150
- return schemaWithUnionType;
151
- }
152
- }
153
-
154
- export default FederationTransform;