UNPKG

4.51 kBJavaScriptView Raw
1import { inspect } from '../jsutils/inspect.mjs';
2import { invariant } from '../jsutils/invariant.mjs';
3import { keyValMap } from '../jsutils/keyValMap.mjs';
4import { naturalCompare } from '../jsutils/naturalCompare.mjs';
5import {
6 GraphQLEnumType,
7 GraphQLInputObjectType,
8 GraphQLInterfaceType,
9 GraphQLList,
10 GraphQLNonNull,
11 GraphQLObjectType,
12 GraphQLUnionType,
13 isEnumType,
14 isInputObjectType,
15 isInterfaceType,
16 isListType,
17 isNonNullType,
18 isObjectType,
19 isScalarType,
20 isUnionType,
21} from '../type/definition.mjs';
22import { GraphQLDirective } from '../type/directives.mjs';
23import { isIntrospectionType } from '../type/introspection.mjs';
24import { GraphQLSchema } from '../type/schema.mjs';
25/**
26 * Sort GraphQLSchema.
27 *
28 * This function returns a sorted copy of the given GraphQLSchema.
29 */
30
31export function lexicographicSortSchema(schema) {
32 const schemaConfig = schema.toConfig();
33 const typeMap = keyValMap(
34 sortByName(schemaConfig.types),
35 (type) => type.name,
36 sortNamedType,
37 );
38 return new GraphQLSchema({
39 ...schemaConfig,
40 types: Object.values(typeMap),
41 directives: sortByName(schemaConfig.directives).map(sortDirective),
42 query: replaceMaybeType(schemaConfig.query),
43 mutation: replaceMaybeType(schemaConfig.mutation),
44 subscription: replaceMaybeType(schemaConfig.subscription),
45 });
46
47 function replaceType(type) {
48 if (isListType(type)) {
49 // @ts-expect-error
50 return new GraphQLList(replaceType(type.ofType));
51 } else if (isNonNullType(type)) {
52 // @ts-expect-error
53 return new GraphQLNonNull(replaceType(type.ofType));
54 } // @ts-expect-error FIXME: TS Conversion
55
56 return replaceNamedType(type);
57 }
58
59 function replaceNamedType(type) {
60 return typeMap[type.name];
61 }
62
63 function replaceMaybeType(maybeType) {
64 return maybeType && replaceNamedType(maybeType);
65 }
66
67 function sortDirective(directive) {
68 const config = directive.toConfig();
69 return new GraphQLDirective({
70 ...config,
71 locations: sortBy(config.locations, (x) => x),
72 args: sortArgs(config.args),
73 });
74 }
75
76 function sortArgs(args) {
77 return sortObjMap(args, (arg) => ({ ...arg, type: replaceType(arg.type) }));
78 }
79
80 function sortFields(fieldsMap) {
81 return sortObjMap(fieldsMap, (field) => ({
82 ...field,
83 type: replaceType(field.type),
84 args: field.args && sortArgs(field.args),
85 }));
86 }
87
88 function sortInputFields(fieldsMap) {
89 return sortObjMap(fieldsMap, (field) => ({
90 ...field,
91 type: replaceType(field.type),
92 }));
93 }
94
95 function sortTypes(array) {
96 return sortByName(array).map(replaceNamedType);
97 }
98
99 function sortNamedType(type) {
100 if (isScalarType(type) || isIntrospectionType(type)) {
101 return type;
102 }
103
104 if (isObjectType(type)) {
105 const config = type.toConfig();
106 return new GraphQLObjectType({
107 ...config,
108 interfaces: () => sortTypes(config.interfaces),
109 fields: () => sortFields(config.fields),
110 });
111 }
112
113 if (isInterfaceType(type)) {
114 const config = type.toConfig();
115 return new GraphQLInterfaceType({
116 ...config,
117 interfaces: () => sortTypes(config.interfaces),
118 fields: () => sortFields(config.fields),
119 });
120 }
121
122 if (isUnionType(type)) {
123 const config = type.toConfig();
124 return new GraphQLUnionType({
125 ...config,
126 types: () => sortTypes(config.types),
127 });
128 }
129
130 if (isEnumType(type)) {
131 const config = type.toConfig();
132 return new GraphQLEnumType({
133 ...config,
134 values: sortObjMap(config.values, (value) => value),
135 });
136 }
137
138 if (isInputObjectType(type)) {
139 const config = type.toConfig();
140 return new GraphQLInputObjectType({
141 ...config,
142 fields: () => sortInputFields(config.fields),
143 });
144 }
145 /* c8 ignore next 3 */
146 // Not reachable, all possible types have been considered.
147
148 false || invariant(false, 'Unexpected type: ' + inspect(type));
149 }
150}
151
152function sortObjMap(map, sortValueFn) {
153 const sortedMap = Object.create(null);
154
155 for (const key of Object.keys(map).sort(naturalCompare)) {
156 sortedMap[key] = sortValueFn(map[key]);
157 }
158
159 return sortedMap;
160}
161
162function sortByName(array) {
163 return sortBy(array, (obj) => obj.name);
164}
165
166function sortBy(array, mapToKey) {
167 return array.slice().sort((obj1, obj2) => {
168 const key1 = mapToKey(obj1);
169 const key2 = mapToKey(obj2);
170 return naturalCompare(key1, key2);
171 });
172}