1 | import { inspect } from '../jsutils/inspect.mjs';
|
2 | import { invariant } from '../jsutils/invariant.mjs';
|
3 | import { keyValMap } from '../jsutils/keyValMap.mjs';
|
4 | import { naturalCompare } from '../jsutils/naturalCompare.mjs';
|
5 | import {
|
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';
|
22 | import { GraphQLDirective } from '../type/directives.mjs';
|
23 | import { isIntrospectionType } from '../type/introspection.mjs';
|
24 | import { GraphQLSchema } from '../type/schema.mjs';
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | export 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 |
|
50 | return new GraphQLList(replaceType(type.ofType));
|
51 | } else if (isNonNullType(type)) {
|
52 |
|
53 | return new GraphQLNonNull(replaceType(type.ofType));
|
54 | }
|
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 |
|
146 |
|
147 |
|
148 | false || invariant(false, 'Unexpected type: ' + inspect(type));
|
149 | }
|
150 | }
|
151 |
|
152 | function 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 |
|
162 | function sortByName(array) {
|
163 | return sortBy(array, (obj) => obj.name);
|
164 | }
|
165 |
|
166 | function 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 | }
|