1 | import { GraphQLObjectType, GraphQLSchema, isInterfaceType, isEnumType, isObjectType, isScalarType, isUnionType, isInputObjectType, GraphQLInputObjectType, GraphQLInterfaceType, isLeafType, isListType, isNonNullType, isNamedType, GraphQLList, GraphQLNonNull, GraphQLEnumType, Kind, } from 'graphql';
|
2 | import { getObjectTypeFromTypeMap } from './getObjectTypeFromTypeMap.js';
|
3 | import { MapperKind, } from './Interfaces.js';
|
4 | import { rewireTypes } from './rewire.js';
|
5 | import { serializeInputValue, parseInputValue } from './transformInputValue.js';
|
6 | export function mapSchema(schema, schemaMapper = {}) {
|
7 | const newTypeMap = mapArguments(mapFields(mapTypes(mapDefaultValues(mapEnumValues(mapTypes(mapDefaultValues(schema.getTypeMap(), schema, serializeInputValue), schema, schemaMapper, type => isLeafType(type)), schema, schemaMapper), schema, parseInputValue), schema, schemaMapper, type => !isLeafType(type)), schema, schemaMapper), schema, schemaMapper);
|
8 | const originalDirectives = schema.getDirectives();
|
9 | const newDirectives = mapDirectives(originalDirectives, schema, schemaMapper);
|
10 | const { typeMap, directives } = rewireTypes(newTypeMap, newDirectives);
|
11 | return new GraphQLSchema({
|
12 | ...schema.toConfig(),
|
13 | query: getObjectTypeFromTypeMap(typeMap, getObjectTypeFromTypeMap(newTypeMap, schema.getQueryType())),
|
14 | mutation: getObjectTypeFromTypeMap(typeMap, getObjectTypeFromTypeMap(newTypeMap, schema.getMutationType())),
|
15 | subscription: getObjectTypeFromTypeMap(typeMap, getObjectTypeFromTypeMap(newTypeMap, schema.getSubscriptionType())),
|
16 | types: Object.values(typeMap),
|
17 | directives,
|
18 | });
|
19 | }
|
20 | function mapTypes(originalTypeMap, schema, schemaMapper, testFn = () => true) {
|
21 | const newTypeMap = {};
|
22 | for (const typeName in originalTypeMap) {
|
23 | if (!typeName.startsWith('__')) {
|
24 | const originalType = originalTypeMap[typeName];
|
25 | if (originalType == null || !testFn(originalType)) {
|
26 | newTypeMap[typeName] = originalType;
|
27 | continue;
|
28 | }
|
29 | const typeMapper = getTypeMapper(schema, schemaMapper, typeName);
|
30 | if (typeMapper == null) {
|
31 | newTypeMap[typeName] = originalType;
|
32 | continue;
|
33 | }
|
34 | const maybeNewType = typeMapper(originalType, schema);
|
35 | if (maybeNewType === undefined) {
|
36 | newTypeMap[typeName] = originalType;
|
37 | continue;
|
38 | }
|
39 | newTypeMap[typeName] = maybeNewType;
|
40 | }
|
41 | }
|
42 | return newTypeMap;
|
43 | }
|
44 | function mapEnumValues(originalTypeMap, schema, schemaMapper) {
|
45 | const enumValueMapper = getEnumValueMapper(schemaMapper);
|
46 | if (!enumValueMapper) {
|
47 | return originalTypeMap;
|
48 | }
|
49 | return mapTypes(originalTypeMap, schema, {
|
50 | [MapperKind.ENUM_TYPE]: type => {
|
51 | const config = type.toConfig();
|
52 | const originalEnumValueConfigMap = config.values;
|
53 | const newEnumValueConfigMap = {};
|
54 | for (const externalValue in originalEnumValueConfigMap) {
|
55 | const originalEnumValueConfig = originalEnumValueConfigMap[externalValue];
|
56 | const mappedEnumValue = enumValueMapper(originalEnumValueConfig, type.name, schema, externalValue);
|
57 | if (mappedEnumValue === undefined) {
|
58 | newEnumValueConfigMap[externalValue] = originalEnumValueConfig;
|
59 | }
|
60 | else if (Array.isArray(mappedEnumValue)) {
|
61 | const [newExternalValue, newEnumValueConfig] = mappedEnumValue;
|
62 | newEnumValueConfigMap[newExternalValue] =
|
63 | newEnumValueConfig === undefined ? originalEnumValueConfig : newEnumValueConfig;
|
64 | }
|
65 | else if (mappedEnumValue !== null) {
|
66 | newEnumValueConfigMap[externalValue] = mappedEnumValue;
|
67 | }
|
68 | }
|
69 | return correctASTNodes(new GraphQLEnumType({
|
70 | ...config,
|
71 | values: newEnumValueConfigMap,
|
72 | }));
|
73 | },
|
74 | }, type => isEnumType(type));
|
75 | }
|
76 | function mapDefaultValues(originalTypeMap, schema, fn) {
|
77 | const newTypeMap = mapArguments(originalTypeMap, schema, {
|
78 | [MapperKind.ARGUMENT]: argumentConfig => {
|
79 | if (argumentConfig.defaultValue === undefined) {
|
80 | return argumentConfig;
|
81 | }
|
82 | const maybeNewType = getNewType(originalTypeMap, argumentConfig.type);
|
83 | if (maybeNewType != null) {
|
84 | return {
|
85 | ...argumentConfig,
|
86 | defaultValue: fn(maybeNewType, argumentConfig.defaultValue),
|
87 | };
|
88 | }
|
89 | },
|
90 | });
|
91 | return mapFields(newTypeMap, schema, {
|
92 | [MapperKind.INPUT_OBJECT_FIELD]: inputFieldConfig => {
|
93 | if (inputFieldConfig.defaultValue === undefined) {
|
94 | return inputFieldConfig;
|
95 | }
|
96 | const maybeNewType = getNewType(newTypeMap, inputFieldConfig.type);
|
97 | if (maybeNewType != null) {
|
98 | return {
|
99 | ...inputFieldConfig,
|
100 | defaultValue: fn(maybeNewType, inputFieldConfig.defaultValue),
|
101 | };
|
102 | }
|
103 | },
|
104 | });
|
105 | }
|
106 | function getNewType(newTypeMap, type) {
|
107 | if (isListType(type)) {
|
108 | const newType = getNewType(newTypeMap, type.ofType);
|
109 | return newType != null ? new GraphQLList(newType) : null;
|
110 | }
|
111 | else if (isNonNullType(type)) {
|
112 | const newType = getNewType(newTypeMap, type.ofType);
|
113 | return newType != null ? new GraphQLNonNull(newType) : null;
|
114 | }
|
115 | else if (isNamedType(type)) {
|
116 | const newType = newTypeMap[type.name];
|
117 | return newType != null ? newType : null;
|
118 | }
|
119 | return null;
|
120 | }
|
121 | function mapFields(originalTypeMap, schema, schemaMapper) {
|
122 | const newTypeMap = {};
|
123 | for (const typeName in originalTypeMap) {
|
124 | if (!typeName.startsWith('__')) {
|
125 | const originalType = originalTypeMap[typeName];
|
126 | if (!isObjectType(originalType) && !isInterfaceType(originalType) && !isInputObjectType(originalType)) {
|
127 | newTypeMap[typeName] = originalType;
|
128 | continue;
|
129 | }
|
130 | const fieldMapper = getFieldMapper(schema, schemaMapper, typeName);
|
131 | if (fieldMapper == null) {
|
132 | newTypeMap[typeName] = originalType;
|
133 | continue;
|
134 | }
|
135 | const config = originalType.toConfig();
|
136 | const originalFieldConfigMap = config.fields;
|
137 | const newFieldConfigMap = {};
|
138 | for (const fieldName in originalFieldConfigMap) {
|
139 | const originalFieldConfig = originalFieldConfigMap[fieldName];
|
140 | const mappedField = fieldMapper(originalFieldConfig, fieldName, typeName, schema);
|
141 | if (mappedField === undefined) {
|
142 | newFieldConfigMap[fieldName] = originalFieldConfig;
|
143 | }
|
144 | else if (Array.isArray(mappedField)) {
|
145 | const [newFieldName, newFieldConfig] = mappedField;
|
146 | if (newFieldConfig.astNode != null) {
|
147 | newFieldConfig.astNode = {
|
148 | ...newFieldConfig.astNode,
|
149 | name: {
|
150 | ...newFieldConfig.astNode.name,
|
151 | value: newFieldName,
|
152 | },
|
153 | };
|
154 | }
|
155 | newFieldConfigMap[newFieldName] = newFieldConfig === undefined ? originalFieldConfig : newFieldConfig;
|
156 | }
|
157 | else if (mappedField !== null) {
|
158 | newFieldConfigMap[fieldName] = mappedField;
|
159 | }
|
160 | }
|
161 | if (isObjectType(originalType)) {
|
162 | newTypeMap[typeName] = correctASTNodes(new GraphQLObjectType({
|
163 | ...config,
|
164 | fields: newFieldConfigMap,
|
165 | }));
|
166 | }
|
167 | else if (isInterfaceType(originalType)) {
|
168 | newTypeMap[typeName] = correctASTNodes(new GraphQLInterfaceType({
|
169 | ...config,
|
170 | fields: newFieldConfigMap,
|
171 | }));
|
172 | }
|
173 | else {
|
174 | newTypeMap[typeName] = correctASTNodes(new GraphQLInputObjectType({
|
175 | ...config,
|
176 | fields: newFieldConfigMap,
|
177 | }));
|
178 | }
|
179 | }
|
180 | }
|
181 | return newTypeMap;
|
182 | }
|
183 | function mapArguments(originalTypeMap, schema, schemaMapper) {
|
184 | const newTypeMap = {};
|
185 | for (const typeName in originalTypeMap) {
|
186 | if (!typeName.startsWith('__')) {
|
187 | const originalType = originalTypeMap[typeName];
|
188 | if (!isObjectType(originalType) && !isInterfaceType(originalType)) {
|
189 | newTypeMap[typeName] = originalType;
|
190 | continue;
|
191 | }
|
192 | const argumentMapper = getArgumentMapper(schemaMapper);
|
193 | if (argumentMapper == null) {
|
194 | newTypeMap[typeName] = originalType;
|
195 | continue;
|
196 | }
|
197 | const config = originalType.toConfig();
|
198 | const originalFieldConfigMap = config.fields;
|
199 | const newFieldConfigMap = {};
|
200 | for (const fieldName in originalFieldConfigMap) {
|
201 | const originalFieldConfig = originalFieldConfigMap[fieldName];
|
202 | const originalArgumentConfigMap = originalFieldConfig.args;
|
203 | if (originalArgumentConfigMap == null) {
|
204 | newFieldConfigMap[fieldName] = originalFieldConfig;
|
205 | continue;
|
206 | }
|
207 | const argumentNames = Object.keys(originalArgumentConfigMap);
|
208 | if (!argumentNames.length) {
|
209 | newFieldConfigMap[fieldName] = originalFieldConfig;
|
210 | continue;
|
211 | }
|
212 | const newArgumentConfigMap = {};
|
213 | for (const argumentName of argumentNames) {
|
214 | const originalArgumentConfig = originalArgumentConfigMap[argumentName];
|
215 | const mappedArgument = argumentMapper(originalArgumentConfig, fieldName, typeName, schema);
|
216 | if (mappedArgument === undefined) {
|
217 | newArgumentConfigMap[argumentName] = originalArgumentConfig;
|
218 | }
|
219 | else if (Array.isArray(mappedArgument)) {
|
220 | const [newArgumentName, newArgumentConfig] = mappedArgument;
|
221 | newArgumentConfigMap[newArgumentName] = newArgumentConfig;
|
222 | }
|
223 | else if (mappedArgument !== null) {
|
224 | newArgumentConfigMap[argumentName] = mappedArgument;
|
225 | }
|
226 | }
|
227 | newFieldConfigMap[fieldName] = {
|
228 | ...originalFieldConfig,
|
229 | args: newArgumentConfigMap,
|
230 | };
|
231 | }
|
232 | if (isObjectType(originalType)) {
|
233 | newTypeMap[typeName] = new GraphQLObjectType({
|
234 | ...config,
|
235 | fields: newFieldConfigMap,
|
236 | });
|
237 | }
|
238 | else if (isInterfaceType(originalType)) {
|
239 | newTypeMap[typeName] = new GraphQLInterfaceType({
|
240 | ...config,
|
241 | fields: newFieldConfigMap,
|
242 | });
|
243 | }
|
244 | else {
|
245 | newTypeMap[typeName] = new GraphQLInputObjectType({
|
246 | ...config,
|
247 | fields: newFieldConfigMap,
|
248 | });
|
249 | }
|
250 | }
|
251 | }
|
252 | return newTypeMap;
|
253 | }
|
254 | function mapDirectives(originalDirectives, schema, schemaMapper) {
|
255 | const directiveMapper = getDirectiveMapper(schemaMapper);
|
256 | if (directiveMapper == null) {
|
257 | return originalDirectives.slice();
|
258 | }
|
259 | const newDirectives = [];
|
260 | for (const directive of originalDirectives) {
|
261 | const mappedDirective = directiveMapper(directive, schema);
|
262 | if (mappedDirective === undefined) {
|
263 | newDirectives.push(directive);
|
264 | }
|
265 | else if (mappedDirective !== null) {
|
266 | newDirectives.push(mappedDirective);
|
267 | }
|
268 | }
|
269 | return newDirectives;
|
270 | }
|
271 | function getTypeSpecifiers(schema, typeName) {
|
272 | var _a, _b, _c;
|
273 | const type = schema.getType(typeName);
|
274 | const specifiers = [MapperKind.TYPE];
|
275 | if (isObjectType(type)) {
|
276 | specifiers.push(MapperKind.COMPOSITE_TYPE, MapperKind.OBJECT_TYPE);
|
277 | if (typeName === ((_a = schema.getQueryType()) === null || _a === void 0 ? void 0 : _a.name)) {
|
278 | specifiers.push(MapperKind.ROOT_OBJECT, MapperKind.QUERY);
|
279 | }
|
280 | else if (typeName === ((_b = schema.getMutationType()) === null || _b === void 0 ? void 0 : _b.name)) {
|
281 | specifiers.push(MapperKind.ROOT_OBJECT, MapperKind.MUTATION);
|
282 | }
|
283 | else if (typeName === ((_c = schema.getSubscriptionType()) === null || _c === void 0 ? void 0 : _c.name)) {
|
284 | specifiers.push(MapperKind.ROOT_OBJECT, MapperKind.SUBSCRIPTION);
|
285 | }
|
286 | }
|
287 | else if (isInputObjectType(type)) {
|
288 | specifiers.push(MapperKind.INPUT_OBJECT_TYPE);
|
289 | }
|
290 | else if (isInterfaceType(type)) {
|
291 | specifiers.push(MapperKind.COMPOSITE_TYPE, MapperKind.ABSTRACT_TYPE, MapperKind.INTERFACE_TYPE);
|
292 | }
|
293 | else if (isUnionType(type)) {
|
294 | specifiers.push(MapperKind.COMPOSITE_TYPE, MapperKind.ABSTRACT_TYPE, MapperKind.UNION_TYPE);
|
295 | }
|
296 | else if (isEnumType(type)) {
|
297 | specifiers.push(MapperKind.ENUM_TYPE);
|
298 | }
|
299 | else if (isScalarType(type)) {
|
300 | specifiers.push(MapperKind.SCALAR_TYPE);
|
301 | }
|
302 | return specifiers;
|
303 | }
|
304 | function getTypeMapper(schema, schemaMapper, typeName) {
|
305 | const specifiers = getTypeSpecifiers(schema, typeName);
|
306 | let typeMapper;
|
307 | const stack = [...specifiers];
|
308 | while (!typeMapper && stack.length > 0) {
|
309 |
|
310 | const next = stack.pop();
|
311 | typeMapper = schemaMapper[next];
|
312 | }
|
313 | return typeMapper != null ? typeMapper : null;
|
314 | }
|
315 | function getFieldSpecifiers(schema, typeName) {
|
316 | var _a, _b, _c;
|
317 | const type = schema.getType(typeName);
|
318 | const specifiers = [MapperKind.FIELD];
|
319 | if (isObjectType(type)) {
|
320 | specifiers.push(MapperKind.COMPOSITE_FIELD, MapperKind.OBJECT_FIELD);
|
321 | if (typeName === ((_a = schema.getQueryType()) === null || _a === void 0 ? void 0 : _a.name)) {
|
322 | specifiers.push(MapperKind.ROOT_FIELD, MapperKind.QUERY_ROOT_FIELD);
|
323 | }
|
324 | else if (typeName === ((_b = schema.getMutationType()) === null || _b === void 0 ? void 0 : _b.name)) {
|
325 | specifiers.push(MapperKind.ROOT_FIELD, MapperKind.MUTATION_ROOT_FIELD);
|
326 | }
|
327 | else if (typeName === ((_c = schema.getSubscriptionType()) === null || _c === void 0 ? void 0 : _c.name)) {
|
328 | specifiers.push(MapperKind.ROOT_FIELD, MapperKind.SUBSCRIPTION_ROOT_FIELD);
|
329 | }
|
330 | }
|
331 | else if (isInterfaceType(type)) {
|
332 | specifiers.push(MapperKind.COMPOSITE_FIELD, MapperKind.INTERFACE_FIELD);
|
333 | }
|
334 | else if (isInputObjectType(type)) {
|
335 | specifiers.push(MapperKind.INPUT_OBJECT_FIELD);
|
336 | }
|
337 | return specifiers;
|
338 | }
|
339 | function getFieldMapper(schema, schemaMapper, typeName) {
|
340 | const specifiers = getFieldSpecifiers(schema, typeName);
|
341 | let fieldMapper;
|
342 | const stack = [...specifiers];
|
343 | while (!fieldMapper && stack.length > 0) {
|
344 |
|
345 | const next = stack.pop();
|
346 |
|
347 | fieldMapper = schemaMapper[next];
|
348 | }
|
349 | return fieldMapper !== null && fieldMapper !== void 0 ? fieldMapper : null;
|
350 | }
|
351 | function getArgumentMapper(schemaMapper) {
|
352 | const argumentMapper = schemaMapper[MapperKind.ARGUMENT];
|
353 | return argumentMapper != null ? argumentMapper : null;
|
354 | }
|
355 | function getDirectiveMapper(schemaMapper) {
|
356 | const directiveMapper = schemaMapper[MapperKind.DIRECTIVE];
|
357 | return directiveMapper != null ? directiveMapper : null;
|
358 | }
|
359 | function getEnumValueMapper(schemaMapper) {
|
360 | const enumValueMapper = schemaMapper[MapperKind.ENUM_VALUE];
|
361 | return enumValueMapper != null ? enumValueMapper : null;
|
362 | }
|
363 | export function correctASTNodes(type) {
|
364 | if (isObjectType(type)) {
|
365 | const config = type.toConfig();
|
366 | if (config.astNode != null) {
|
367 | const fields = [];
|
368 | for (const fieldName in config.fields) {
|
369 | const fieldConfig = config.fields[fieldName];
|
370 | if (fieldConfig.astNode != null) {
|
371 | fields.push(fieldConfig.astNode);
|
372 | }
|
373 | }
|
374 | config.astNode = {
|
375 | ...config.astNode,
|
376 | kind: Kind.OBJECT_TYPE_DEFINITION,
|
377 | fields,
|
378 | };
|
379 | }
|
380 | if (config.extensionASTNodes != null) {
|
381 | config.extensionASTNodes = config.extensionASTNodes.map(node => ({
|
382 | ...node,
|
383 | kind: Kind.OBJECT_TYPE_EXTENSION,
|
384 | fields: undefined,
|
385 | }));
|
386 | }
|
387 | return new GraphQLObjectType(config);
|
388 | }
|
389 | else if (isInterfaceType(type)) {
|
390 | const config = type.toConfig();
|
391 | if (config.astNode != null) {
|
392 | const fields = [];
|
393 | for (const fieldName in config.fields) {
|
394 | const fieldConfig = config.fields[fieldName];
|
395 | if (fieldConfig.astNode != null) {
|
396 | fields.push(fieldConfig.astNode);
|
397 | }
|
398 | }
|
399 | config.astNode = {
|
400 | ...config.astNode,
|
401 | kind: Kind.INTERFACE_TYPE_DEFINITION,
|
402 | fields,
|
403 | };
|
404 | }
|
405 | if (config.extensionASTNodes != null) {
|
406 | config.extensionASTNodes = config.extensionASTNodes.map(node => ({
|
407 | ...node,
|
408 | kind: Kind.INTERFACE_TYPE_EXTENSION,
|
409 | fields: undefined,
|
410 | }));
|
411 | }
|
412 | return new GraphQLInterfaceType(config);
|
413 | }
|
414 | else if (isInputObjectType(type)) {
|
415 | const config = type.toConfig();
|
416 | if (config.astNode != null) {
|
417 | const fields = [];
|
418 | for (const fieldName in config.fields) {
|
419 | const fieldConfig = config.fields[fieldName];
|
420 | if (fieldConfig.astNode != null) {
|
421 | fields.push(fieldConfig.astNode);
|
422 | }
|
423 | }
|
424 | config.astNode = {
|
425 | ...config.astNode,
|
426 | kind: Kind.INPUT_OBJECT_TYPE_DEFINITION,
|
427 | fields,
|
428 | };
|
429 | }
|
430 | if (config.extensionASTNodes != null) {
|
431 | config.extensionASTNodes = config.extensionASTNodes.map(node => ({
|
432 | ...node,
|
433 | kind: Kind.INPUT_OBJECT_TYPE_EXTENSION,
|
434 | fields: undefined,
|
435 | }));
|
436 | }
|
437 | return new GraphQLInputObjectType(config);
|
438 | }
|
439 | else if (isEnumType(type)) {
|
440 | const config = type.toConfig();
|
441 | if (config.astNode != null) {
|
442 | const values = [];
|
443 | for (const enumKey in config.values) {
|
444 | const enumValueConfig = config.values[enumKey];
|
445 | if (enumValueConfig.astNode != null) {
|
446 | values.push(enumValueConfig.astNode);
|
447 | }
|
448 | }
|
449 | config.astNode = {
|
450 | ...config.astNode,
|
451 | values,
|
452 | };
|
453 | }
|
454 | if (config.extensionASTNodes != null) {
|
455 | config.extensionASTNodes = config.extensionASTNodes.map(node => ({
|
456 | ...node,
|
457 | values: undefined,
|
458 | }));
|
459 | }
|
460 | return new GraphQLEnumType(config);
|
461 | }
|
462 | else {
|
463 | return type;
|
464 | }
|
465 | }
|