UNPKG

format-graphql

Version:

Formats GraphQL schema definition language (SDL) document.

109 lines (95 loc) 2.28 kB
// @flow import { print, parse, } from 'graphql'; import type {ASTNode} from 'graphql'; import {getOptions} from './optionalize'; import type {OptionsType} from './optionalize'; const sortSchema = (key, node: ASTNode, options: OptionsType) => { const value = node[key]; const { sortArguments, sortDefinitions, sortEnums, sortFields, } = options; if ( sortDefinitions && key === 'definitions' || sortEnums && node.kind === 'EnumTypeDefinition' && key === 'values' || sortFields && key === 'fields' || sortArguments && key === 'arguments' ) { return value.slice().sort((a, b) => { if (a.kind === 'SchemaDefinition') { return -1; } if (b.kind === 'SchemaDefinition') { return 1; } return a.name.value.localeCompare(b.name.value); }); } return value; }; /** * We only care about rearranging: * - definitions * - enums * - fields * - arguments * * A GraphQL Schema AST looks something like this: * * { * "definitions": [ * { * fields: [ * { * arguments: [ * ... * ] * } * ... * ], * }, * { * values: [ * ... * ], * }, * ... * ] * } * * Note that there are no cycles - we don't need to recurse through the whole * AST. There's a finite nest depth of 3 node types for us to walk down: * * <start> -> definitions -> fields -> arguments * * or, for enums: * * <start> -> definitions -> values */ const walkAST = (node: ASTNode, options: OptionsType, key: ?string) => { // Map a node type to the child node type we should walk down next const nextKey = { arguments: null, definitions: 'fields', EnumTypeDefinition: 'values', fields: 'arguments', }; if (!key) { return node; } if (!Array.isArray(node[key])) { return node; } node[key] = sortSchema(key, node, options).map((child) => { return walkAST(child, options, nextKey[child.kind] || nextKey[key]); }); return node; }; export default (schemaSdl: string, options?: $Shape<OptionsType>): string => { return print(walkAST(parse(schemaSdl), getOptions(options), 'definitions')); };