Spaces:
Running
Running
| import { inspect } from '../jsutils/inspect.mjs'; | |
| import { invariant } from '../jsutils/invariant.mjs'; | |
| import { keyValMap } from '../jsutils/keyValMap.mjs'; | |
| import { naturalCompare } from '../jsutils/naturalCompare.mjs'; | |
| import { | |
| GraphQLEnumType, | |
| GraphQLInputObjectType, | |
| GraphQLInterfaceType, | |
| GraphQLList, | |
| GraphQLNonNull, | |
| GraphQLObjectType, | |
| GraphQLUnionType, | |
| isEnumType, | |
| isInputObjectType, | |
| isInterfaceType, | |
| isListType, | |
| isNonNullType, | |
| isObjectType, | |
| isScalarType, | |
| isUnionType, | |
| } from '../type/definition.mjs'; | |
| import { GraphQLDirective } from '../type/directives.mjs'; | |
| import { isIntrospectionType } from '../type/introspection.mjs'; | |
| import { GraphQLSchema } from '../type/schema.mjs'; | |
| /** | |
| * Sort GraphQLSchema. | |
| * | |
| * This function returns a sorted copy of the given GraphQLSchema. | |
| */ | |
| export function lexicographicSortSchema(schema) { | |
| const schemaConfig = schema.toConfig(); | |
| const typeMap = keyValMap( | |
| sortByName(schemaConfig.types), | |
| (type) => type.name, | |
| sortNamedType, | |
| ); | |
| return new GraphQLSchema({ | |
| ...schemaConfig, | |
| types: Object.values(typeMap), | |
| directives: sortByName(schemaConfig.directives).map(sortDirective), | |
| query: replaceMaybeType(schemaConfig.query), | |
| mutation: replaceMaybeType(schemaConfig.mutation), | |
| subscription: replaceMaybeType(schemaConfig.subscription), | |
| }); | |
| function replaceType(type) { | |
| if (isListType(type)) { | |
| // @ts-expect-error | |
| return new GraphQLList(replaceType(type.ofType)); | |
| } else if (isNonNullType(type)) { | |
| // @ts-expect-error | |
| return new GraphQLNonNull(replaceType(type.ofType)); | |
| } // @ts-expect-error FIXME: TS Conversion | |
| return replaceNamedType(type); | |
| } | |
| function replaceNamedType(type) { | |
| return typeMap[type.name]; | |
| } | |
| function replaceMaybeType(maybeType) { | |
| return maybeType && replaceNamedType(maybeType); | |
| } | |
| function sortDirective(directive) { | |
| const config = directive.toConfig(); | |
| return new GraphQLDirective({ | |
| ...config, | |
| locations: sortBy(config.locations, (x) => x), | |
| args: sortArgs(config.args), | |
| }); | |
| } | |
| function sortArgs(args) { | |
| return sortObjMap(args, (arg) => ({ ...arg, type: replaceType(arg.type) })); | |
| } | |
| function sortFields(fieldsMap) { | |
| return sortObjMap(fieldsMap, (field) => ({ | |
| ...field, | |
| type: replaceType(field.type), | |
| args: field.args && sortArgs(field.args), | |
| })); | |
| } | |
| function sortInputFields(fieldsMap) { | |
| return sortObjMap(fieldsMap, (field) => ({ | |
| ...field, | |
| type: replaceType(field.type), | |
| })); | |
| } | |
| function sortTypes(array) { | |
| return sortByName(array).map(replaceNamedType); | |
| } | |
| function sortNamedType(type) { | |
| if (isScalarType(type) || isIntrospectionType(type)) { | |
| return type; | |
| } | |
| if (isObjectType(type)) { | |
| const config = type.toConfig(); | |
| return new GraphQLObjectType({ | |
| ...config, | |
| interfaces: () => sortTypes(config.interfaces), | |
| fields: () => sortFields(config.fields), | |
| }); | |
| } | |
| if (isInterfaceType(type)) { | |
| const config = type.toConfig(); | |
| return new GraphQLInterfaceType({ | |
| ...config, | |
| interfaces: () => sortTypes(config.interfaces), | |
| fields: () => sortFields(config.fields), | |
| }); | |
| } | |
| if (isUnionType(type)) { | |
| const config = type.toConfig(); | |
| return new GraphQLUnionType({ | |
| ...config, | |
| types: () => sortTypes(config.types), | |
| }); | |
| } | |
| if (isEnumType(type)) { | |
| const config = type.toConfig(); | |
| return new GraphQLEnumType({ | |
| ...config, | |
| values: sortObjMap(config.values, (value) => value), | |
| }); | |
| } | |
| if (isInputObjectType(type)) { | |
| const config = type.toConfig(); | |
| return new GraphQLInputObjectType({ | |
| ...config, | |
| fields: () => sortInputFields(config.fields), | |
| }); | |
| } | |
| /* c8 ignore next 3 */ | |
| // Not reachable, all possible types have been considered. | |
| false || invariant(false, 'Unexpected type: ' + inspect(type)); | |
| } | |
| } | |
| function sortObjMap(map, sortValueFn) { | |
| const sortedMap = Object.create(null); | |
| for (const key of Object.keys(map).sort(naturalCompare)) { | |
| sortedMap[key] = sortValueFn(map[key]); | |
| } | |
| return sortedMap; | |
| } | |
| function sortByName(array) { | |
| return sortBy(array, (obj) => obj.name); | |
| } | |
| function sortBy(array, mapToKey) { | |
| return array.slice().sort((obj1, obj2) => { | |
| const key1 = mapToKey(obj1); | |
| const key2 = mapToKey(obj2); | |
| return naturalCompare(key1, key2); | |
| }); | |
| } | |