From 7f5d2e784f8d2c9d9c5fbcee00cad5a7ec7d6715 Mon Sep 17 00:00:00 2001 From: Ivan Goncharov Date: Tue, 23 Jan 2018 13:08:38 +0200 Subject: [PATCH] Add 'objectValues' JS util function --- src/jsutils/objectValues.js | 18 +++++++++++++++ src/type/introspection.js | 12 ++++------ src/type/schema.js | 10 +++------ src/type/validate.js | 41 ++++++++++++++-------------------- src/utilities/astFromValue.js | 10 ++++----- src/utilities/schemaPrinter.js | 12 +++++----- src/utilities/valueFromAST.js | 15 ++++++------- 7 files changed, 59 insertions(+), 59 deletions(-) create mode 100644 src/jsutils/objectValues.js diff --git a/src/jsutils/objectValues.js b/src/jsutils/objectValues.js new file mode 100644 index 0000000000..e7a4bb1c09 --- /dev/null +++ b/src/jsutils/objectValues.js @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import type { ObjMap } from './ObjMap'; + +declare function objectValues(obj: ObjMap): Array; + +/* eslint-disable no-redeclare */ +// $FlowFixMe workaround for: https://github.com/facebook/flow/issues/2221 +const objectValues = + Object.values || (obj => Object.keys(obj).map(key => obj[key])); +export default objectValues; diff --git a/src/type/introspection.js b/src/type/introspection.js index 759f4b8f2b..af78f42204 100644 --- a/src/type/introspection.js +++ b/src/type/introspection.js @@ -8,6 +8,7 @@ */ import isInvalid from '../jsutils/isInvalid'; +import objectValues from '../jsutils/objectValues'; import { astFromValue } from '../utilities/astFromValue'; import { print } from '../language/printer'; import { @@ -41,8 +42,7 @@ export const __Schema = new GraphQLObjectType({ description: 'A list of all types supported by this server.', type: GraphQLNonNull(GraphQLList(GraphQLNonNull(__Type))), resolve(schema) { - const typeMap = schema.getTypeMap(); - return Object.keys(typeMap).map(key => typeMap[key]); + return objectValues(schema.getTypeMap()); }, }, queryType: { @@ -245,10 +245,7 @@ export const __Type = new GraphQLObjectType({ }, resolve(type, { includeDeprecated }) { if (isObjectType(type) || isInterfaceType(type)) { - const fieldMap = type.getFields(); - let fields = Object.keys(fieldMap).map( - fieldName => fieldMap[fieldName], - ); + let fields = objectValues(type.getFields()); if (!includeDeprecated) { fields = fields.filter(field => !field.deprecationReason); } @@ -292,8 +289,7 @@ export const __Type = new GraphQLObjectType({ type: GraphQLList(GraphQLNonNull(__InputValue)), resolve(type) { if (isInputObjectType(type)) { - const fieldMap = type.getFields(); - return Object.keys(fieldMap).map(fieldName => fieldMap[fieldName]); + return objectValues(type.getFields()); } }, }, diff --git a/src/type/schema.js b/src/type/schema.js index d25a9c69d2..9482a9d116 100644 --- a/src/type/schema.js +++ b/src/type/schema.js @@ -32,6 +32,7 @@ import { __Schema } from './introspection'; import find from '../jsutils/find'; import instanceOf from '../jsutils/instanceOf'; import invariant from '../jsutils/invariant'; +import objectValues from '../jsutils/objectValues'; import type { ObjMap } from '../jsutils/ObjMap'; /** @@ -275,10 +276,7 @@ function typeMapReducer(map: TypeMap, type: ?GraphQLType): TypeMap { } if (isObjectType(type) || isInterfaceType(type)) { - const fieldMap = type.getFields(); - Object.keys(fieldMap).forEach(fieldName => { - const field = fieldMap[fieldName]; - + objectValues(type.getFields()).forEach(field => { if (field.args) { const fieldArgTypes = field.args.map(arg => arg.type); reducedMap = fieldArgTypes.reduce(typeMapReducer, reducedMap); @@ -288,9 +286,7 @@ function typeMapReducer(map: TypeMap, type: ?GraphQLType): TypeMap { } if (isInputObjectType(type)) { - const fieldMap = type.getFields(); - Object.keys(fieldMap).forEach(fieldName => { - const field = fieldMap[fieldName]; + objectValues(type.getFields()).forEach(field => { reducedMap = typeMapReducer(reducedMap, field.type); }); } diff --git a/src/type/validate.js b/src/type/validate.js index 4d6feaa9f6..decc7f3049 100644 --- a/src/type/validate.js +++ b/src/type/validate.js @@ -32,6 +32,7 @@ import { isSchema } from './schema'; import type { GraphQLSchema } from './schema'; import find from '../jsutils/find'; import invariant from '../jsutils/invariant'; +import objectValues from '../jsutils/objectValues'; import { GraphQLError } from '../error/GraphQLError'; import type { ASTNode, @@ -232,9 +233,7 @@ function validateName( function validateTypes(context: SchemaValidationContext): void { const typeMap = context.schema.getTypeMap(); - Object.keys(typeMap).forEach(typeName => { - const type = typeMap[typeName]; - + objectValues(typeMap).forEach(type => { // Ensure all provided types are in fact GraphQL type. if (!isNamedType(type)) { context.reportError( @@ -275,28 +274,25 @@ function validateFields( context: SchemaValidationContext, type: GraphQLObjectType | GraphQLInterfaceType, ): void { - const fieldMap = type.getFields(); - const fieldNames = Object.keys(fieldMap); + const fields = objectValues(type.getFields()); // Objects and Interfaces both must define one or more fields. - if (fieldNames.length === 0) { + if (fields.length === 0) { context.reportError( `Type ${type.name} must define one or more fields.`, getAllObjectOrInterfaceNodes(type), ); } - fieldNames.forEach(fieldName => { - const field = fieldMap[fieldName]; - + fields.forEach(field => { // Ensure they are named correctly. validateName(context, field); // Ensure they were defined at most once. - const fieldNodes = getAllFieldNodes(type, fieldName); + const fieldNodes = getAllFieldNodes(type, field.name); if (fieldNodes.length > 1) { context.reportError( - `Field ${type.name}.${fieldName} can only be defined once.`, + `Field ${type.name}.${field.name} can only be defined once.`, fieldNodes, ); return; // continue loop @@ -305,9 +301,9 @@ function validateFields( // Ensure the type is an output type if (!isOutputType(field.type)) { context.reportError( - `The type of ${type.name}.${fieldName} must be Output Type ` + + `The type of ${type.name}.${field.name} must be Output Type ` + `but got: ${String(field.type)}.`, - getFieldTypeNode(type, fieldName), + getFieldTypeNode(type, field.name), ); } @@ -322,9 +318,9 @@ function validateFields( // Ensure they are unique per field. if (argNames[argName]) { context.reportError( - `Field argument ${type.name}.${fieldName}(${argName}:) can only ` + + `Field argument ${type.name}.${field.name}(${argName}:) can only ` + 'be defined once.', - getAllFieldArgNodes(type, fieldName, argName), + getAllFieldArgNodes(type, field.name, argName), ); } argNames[argName] = true; @@ -332,9 +328,9 @@ function validateFields( // Ensure the type is an input type if (!isInputType(arg.type)) { context.reportError( - `The type of ${type.name}.${fieldName}(${argName}:) must be Input ` + + `The type of ${type.name}.${field.name}(${argName}:) must be Input ` + `Type but got: ${String(arg.type)}.`, - getFieldArgTypeNode(type, fieldName, argName), + getFieldArgTypeNode(type, field.name, argName), ); } }); @@ -537,10 +533,9 @@ function validateInputFields( context: SchemaValidationContext, inputObj: GraphQLInputObjectType, ): void { - const fieldMap = inputObj.getFields(); - const fieldNames = Object.keys(fieldMap); + const fields = objectValues(inputObj.getFields()); - if (fieldNames.length === 0) { + if (fields.length === 0) { context.reportError( `Input Object type ${inputObj.name} must define one or more fields.`, inputObj.astNode, @@ -548,9 +543,7 @@ function validateInputFields( } // Ensure the arguments are valid - fieldNames.forEach(fieldName => { - const field = fieldMap[fieldName]; - + fields.forEach(field => { // Ensure they are named correctly. validateName(context, field); @@ -559,7 +552,7 @@ function validateInputFields( // Ensure the type is an input type if (!isInputType(field.type)) { context.reportError( - `The type of ${inputObj.name}.${fieldName} must be Input Type ` + + `The type of ${inputObj.name}.${field.name} must be Input Type ` + `but got: ${String(field.type)}.`, field.astNode && field.astNode.type, ); diff --git a/src/utilities/astFromValue.js b/src/utilities/astFromValue.js index 4e9f2d257b..a2cf4a6f76 100644 --- a/src/utilities/astFromValue.js +++ b/src/utilities/astFromValue.js @@ -11,6 +11,7 @@ import { forEach, isCollection } from 'iterall'; import isNullish from '../jsutils/isNullish'; import isInvalid from '../jsutils/isInvalid'; +import objectValues from '../jsutils/objectValues'; import type { ValueNode } from '../language/ast'; import { Kind } from '../language/kinds'; import type { GraphQLInputType } from '../type/definition'; @@ -85,15 +86,14 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode { if (_value === null || typeof _value !== 'object') { return null; } - const fields = type.getFields(); + const fields = objectValues(type.getFields()); const fieldNodes = []; - Object.keys(fields).forEach(fieldName => { - const fieldType = fields[fieldName].type; - const fieldValue = astFromValue(_value[fieldName], fieldType); + fields.forEach(field => { + const fieldValue = astFromValue(_value[field.name], field.type); if (fieldValue) { fieldNodes.push({ kind: Kind.OBJECT_FIELD, - name: { kind: Kind.NAME, value: fieldName }, + name: { kind: Kind.NAME, value: field.name }, value: fieldValue, }); } diff --git a/src/utilities/schemaPrinter.js b/src/utilities/schemaPrinter.js index 6dc1e189bc..8515bafef8 100644 --- a/src/utilities/schemaPrinter.js +++ b/src/utilities/schemaPrinter.js @@ -9,6 +9,7 @@ import isNullish from '../jsutils/isNullish'; import isInvalid from '../jsutils/isInvalid'; +import objectValues from '../jsutils/objectValues'; import { astFromValue } from '../utilities/astFromValue'; import { print } from '../language/printer'; import type { GraphQLSchema } from '../type/schema'; @@ -79,9 +80,8 @@ function printFilteredSchema( ): string { const directives = schema.getDirectives().filter(directiveFilter); const typeMap = schema.getTypeMap(); - const types = Object.keys(typeMap) - .sort((name1, name2) => name1.localeCompare(name2)) - .map(typeName => typeMap[typeName]) + const types = objectValues(typeMap) + .sort((type1, type2) => type1.name.localeCompare(type2.name)) .filter(typeFilter); return ( @@ -227,8 +227,7 @@ function printEnumValues(values, options): string { } function printInputObject(type: GraphQLInputObjectType, options): string { - const fieldMap = type.getFields(); - const fields = Object.keys(fieldMap).map(fieldName => fieldMap[fieldName]); + const fields = objectValues(type.getFields()); return ( printDescription(options, type) + `input ${type.name} {\n` + @@ -244,8 +243,7 @@ function printInputObject(type: GraphQLInputObjectType, options): string { } function printFields(options, type) { - const fieldMap = type.getFields(); - const fields = Object.keys(fieldMap).map(fieldName => fieldMap[fieldName]); + const fields = objectValues(type.getFields()); return fields .map( (f, i) => diff --git a/src/utilities/valueFromAST.js b/src/utilities/valueFromAST.js index e391fccbd4..bc885fd69f 100644 --- a/src/utilities/valueFromAST.js +++ b/src/utilities/valueFromAST.js @@ -9,6 +9,7 @@ import keyMap from '../jsutils/keyMap'; import isInvalid from '../jsutils/isInvalid'; +import objectValues from '../jsutils/objectValues'; import type { ObjMap } from '../jsutils/ObjMap'; import { Kind } from '../language/kinds'; import { @@ -116,19 +117,17 @@ export function valueFromAST( return; // Invalid: intentionally return no value. } const coercedObj = Object.create(null); - const fields = type.getFields(); const fieldNodes = keyMap( (valueNode: ObjectValueNode).fields, field => field.name.value, ); - const fieldNames = Object.keys(fields); - for (let i = 0; i < fieldNames.length; i++) { - const fieldName = fieldNames[i]; - const field = fields[fieldName]; - const fieldNode = fieldNodes[fieldName]; + const fields = objectValues(type.getFields()); + for (let i = 0; i < fields.length; i++) { + const field = fields[i]; + const fieldNode = fieldNodes[field.name]; if (!fieldNode || isMissingVariable(fieldNode.value, variables)) { if (!isInvalid(field.defaultValue)) { - coercedObj[fieldName] = field.defaultValue; + coercedObj[field.name] = field.defaultValue; } else if (isNonNullType(field.type)) { return; // Invalid: intentionally return no value. } @@ -138,7 +137,7 @@ export function valueFromAST( if (isInvalid(fieldValue)) { return; // Invalid: intentionally return no value. } - coercedObj[fieldName] = fieldValue; + coercedObj[field.name] = fieldValue; } return coercedObj; }