You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
4.4 KiB
172 lines
4.4 KiB
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); |
|
}); |
|
}
|
|
|