astFromValue.mjs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import { forEach, isCollection } from 'iterall';
  2. import objectValues from '../polyfills/objectValues';
  3. import inspect from '../jsutils/inspect';
  4. import invariant from '../jsutils/invariant';
  5. import isNullish from '../jsutils/isNullish';
  6. import isInvalid from '../jsutils/isInvalid';
  7. import isObjectLike from '../jsutils/isObjectLike';
  8. import { Kind } from '../language/kinds';
  9. import { GraphQLID } from '../type/scalars';
  10. import { isLeafType, isEnumType, isInputObjectType, isListType, isNonNullType } from '../type/definition';
  11. /**
  12. * Produces a GraphQL Value AST given a JavaScript value.
  13. *
  14. * A GraphQL type must be provided, which will be used to interpret different
  15. * JavaScript values.
  16. *
  17. * | JSON Value | GraphQL Value |
  18. * | ------------- | -------------------- |
  19. * | Object | Input Object |
  20. * | Array | List |
  21. * | Boolean | Boolean |
  22. * | String | String / Enum Value |
  23. * | Number | Int / Float |
  24. * | Mixed | Enum Value |
  25. * | null | NullValue |
  26. *
  27. */
  28. export function astFromValue(value, type) {
  29. if (isNonNullType(type)) {
  30. var astValue = astFromValue(value, type.ofType);
  31. if (astValue && astValue.kind === Kind.NULL) {
  32. return null;
  33. }
  34. return astValue;
  35. } // only explicit null, not undefined, NaN
  36. if (value === null) {
  37. return {
  38. kind: Kind.NULL
  39. };
  40. } // undefined, NaN
  41. if (isInvalid(value)) {
  42. return null;
  43. } // Convert JavaScript array to GraphQL list. If the GraphQLType is a list, but
  44. // the value is not an array, convert the value using the list's item type.
  45. if (isListType(type)) {
  46. var itemType = type.ofType;
  47. if (isCollection(value)) {
  48. var valuesNodes = [];
  49. forEach(value, function (item) {
  50. var itemNode = astFromValue(item, itemType);
  51. if (itemNode) {
  52. valuesNodes.push(itemNode);
  53. }
  54. });
  55. return {
  56. kind: Kind.LIST,
  57. values: valuesNodes
  58. };
  59. }
  60. return astFromValue(value, itemType);
  61. } // Populate the fields of the input object by creating ASTs from each value
  62. // in the JavaScript object according to the fields in the input type.
  63. if (isInputObjectType(type)) {
  64. if (!isObjectLike(value)) {
  65. return null;
  66. }
  67. var fieldNodes = [];
  68. for (var _i2 = 0, _objectValues2 = objectValues(type.getFields()); _i2 < _objectValues2.length; _i2++) {
  69. var field = _objectValues2[_i2];
  70. var fieldValue = astFromValue(value[field.name], field.type);
  71. if (fieldValue) {
  72. fieldNodes.push({
  73. kind: Kind.OBJECT_FIELD,
  74. name: {
  75. kind: Kind.NAME,
  76. value: field.name
  77. },
  78. value: fieldValue
  79. });
  80. }
  81. }
  82. return {
  83. kind: Kind.OBJECT,
  84. fields: fieldNodes
  85. };
  86. }
  87. /* istanbul ignore else */
  88. if (isLeafType(type)) {
  89. // Since value is an internally represented value, it must be serialized
  90. // to an externally represented value before converting into an AST.
  91. var serialized = type.serialize(value);
  92. if (isNullish(serialized)) {
  93. return null;
  94. } // Others serialize based on their corresponding JavaScript scalar types.
  95. if (typeof serialized === 'boolean') {
  96. return {
  97. kind: Kind.BOOLEAN,
  98. value: serialized
  99. };
  100. } // JavaScript numbers can be Int or Float values.
  101. if (typeof serialized === 'number') {
  102. var stringNum = String(serialized);
  103. return integerStringRegExp.test(stringNum) ? {
  104. kind: Kind.INT,
  105. value: stringNum
  106. } : {
  107. kind: Kind.FLOAT,
  108. value: stringNum
  109. };
  110. }
  111. if (typeof serialized === 'string') {
  112. // Enum types use Enum literals.
  113. if (isEnumType(type)) {
  114. return {
  115. kind: Kind.ENUM,
  116. value: serialized
  117. };
  118. } // ID types can use Int literals.
  119. if (type === GraphQLID && integerStringRegExp.test(serialized)) {
  120. return {
  121. kind: Kind.INT,
  122. value: serialized
  123. };
  124. }
  125. return {
  126. kind: Kind.STRING,
  127. value: serialized
  128. };
  129. }
  130. throw new TypeError("Cannot convert value to AST: ".concat(inspect(serialized)));
  131. } // Not reachable. All possible input types have been considered.
  132. /* istanbul ignore next */
  133. invariant(false, 'Unexpected input type: ' + inspect(type));
  134. }
  135. /**
  136. * IntValue:
  137. * - NegativeSign? 0
  138. * - NegativeSign? NonZeroDigit ( Digit+ )?
  139. */
  140. var integerStringRegExp = /^-?(?:0|[1-9][0-9]*)$/;