UNPKG

19.8 kBJavaScriptView Raw
1import { GraphQLObjectType, GraphQLSchema, isInterfaceType, isEnumType, isObjectType, isScalarType, isUnionType, isInputObjectType, GraphQLInputObjectType, GraphQLInterfaceType, isLeafType, isListType, isNonNullType, isNamedType, GraphQLList, GraphQLNonNull, GraphQLEnumType, Kind, } from 'graphql';
2import { getObjectTypeFromTypeMap } from './getObjectTypeFromTypeMap.js';
3import { MapperKind, } from './Interfaces.js';
4import { rewireTypes } from './rewire.js';
5import { serializeInputValue, parseInputValue } from './transformInputValue.js';
6export 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}
20function 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}
44function 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}
76function 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}
106function 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}
121function 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}
183function 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}
254function 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}
271function 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}
304function getTypeMapper(schema, schemaMapper, typeName) {
305 const specifiers = getTypeSpecifiers(schema, typeName);
306 let typeMapper;
307 const stack = [...specifiers];
308 while (!typeMapper && stack.length > 0) {
309 // It is safe to use the ! operator here as we check the length.
310 const next = stack.pop();
311 typeMapper = schemaMapper[next];
312 }
313 return typeMapper != null ? typeMapper : null;
314}
315function 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}
339function getFieldMapper(schema, schemaMapper, typeName) {
340 const specifiers = getFieldSpecifiers(schema, typeName);
341 let fieldMapper;
342 const stack = [...specifiers];
343 while (!fieldMapper && stack.length > 0) {
344 // It is safe to use the ! operator here as we check the length.
345 const next = stack.pop();
346 // TODO: fix this as unknown cast
347 fieldMapper = schemaMapper[next];
348 }
349 return fieldMapper !== null && fieldMapper !== void 0 ? fieldMapper : null;
350}
351function getArgumentMapper(schemaMapper) {
352 const argumentMapper = schemaMapper[MapperKind.ARGUMENT];
353 return argumentMapper != null ? argumentMapper : null;
354}
355function getDirectiveMapper(schemaMapper) {
356 const directiveMapper = schemaMapper[MapperKind.DIRECTIVE];
357 return directiveMapper != null ? directiveMapper : null;
358}
359function getEnumValueMapper(schemaMapper) {
360 const enumValueMapper = schemaMapper[MapperKind.ENUM_VALUE];
361 return enumValueMapper != null ? enumValueMapper : null;
362}
363export 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}