schemaVisitor.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. var __extends = (this && this.__extends) || (function () {
  2. var extendStatics = function (d, b) {
  3. extendStatics = Object.setPrototypeOf ||
  4. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  5. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  6. return extendStatics(d, b);
  7. };
  8. return function (d, b) {
  9. extendStatics(d, b);
  10. function __() { this.constructor = d; }
  11. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  12. };
  13. })();
  14. var __spreadArrays = (this && this.__spreadArrays) || function () {
  15. for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
  16. for (var r = Array(s), k = 0, i = 0; i < il; i++)
  17. for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
  18. r[k] = a[j];
  19. return r;
  20. };
  21. Object.defineProperty(exports, "__esModule", { value: true });
  22. var graphql_1 = require("graphql");
  23. var values_1 = require("graphql/execution/values");
  24. var hasOwn = Object.prototype.hasOwnProperty;
  25. // Abstract base class of any visitor implementation, defining the available
  26. // visitor methods along with their parameter types, and providing a static
  27. // helper function for determining whether a subclass implements a given
  28. // visitor method, as opposed to inheriting one of the stubs defined here.
  29. var SchemaVisitor = /** @class */ (function () {
  30. function SchemaVisitor() {
  31. }
  32. // Determine if this SchemaVisitor (sub)class implements a particular
  33. // visitor method.
  34. SchemaVisitor.implementsVisitorMethod = function (methodName) {
  35. if (!methodName.startsWith('visit')) {
  36. return false;
  37. }
  38. var method = this.prototype[methodName];
  39. if (typeof method !== 'function') {
  40. return false;
  41. }
  42. if (this === SchemaVisitor) {
  43. // The SchemaVisitor class implements every visitor method.
  44. return true;
  45. }
  46. var stub = SchemaVisitor.prototype[methodName];
  47. if (method === stub) {
  48. // If this.prototype[methodName] was just inherited from SchemaVisitor,
  49. // then this class does not really implement the method.
  50. return false;
  51. }
  52. return true;
  53. };
  54. // Concrete subclasses of SchemaVisitor should override one or more of these
  55. // visitor methods, in order to express their interest in handling certain
  56. // schema types/locations. Each method may return null to remove the given
  57. // type from the schema, a non-null value of the same type to update the
  58. // type in the schema, or nothing to leave the type as it was.
  59. /* tslint:disable:no-empty */
  60. SchemaVisitor.prototype.visitSchema = function (schema) { };
  61. SchemaVisitor.prototype.visitScalar = function (scalar) { };
  62. SchemaVisitor.prototype.visitObject = function (object) { };
  63. SchemaVisitor.prototype.visitFieldDefinition = function (field, details) { };
  64. SchemaVisitor.prototype.visitArgumentDefinition = function (argument, details) { };
  65. SchemaVisitor.prototype.visitInterface = function (iface) { };
  66. SchemaVisitor.prototype.visitUnion = function (union) { };
  67. SchemaVisitor.prototype.visitEnum = function (type) { };
  68. SchemaVisitor.prototype.visitEnumValue = function (value, details) { };
  69. SchemaVisitor.prototype.visitInputObject = function (object) { };
  70. SchemaVisitor.prototype.visitInputFieldDefinition = function (field, details) { };
  71. return SchemaVisitor;
  72. }());
  73. exports.SchemaVisitor = SchemaVisitor;
  74. // Generic function for visiting GraphQLSchema objects.
  75. function visitSchema(schema,
  76. // To accommodate as many different visitor patterns as possible, the
  77. // visitSchema function does not simply accept a single instance of the
  78. // SchemaVisitor class, but instead accepts a function that takes the
  79. // current VisitableSchemaType object and the name of a visitor method and
  80. // returns an array of SchemaVisitor instances that implement the visitor
  81. // method and have an interest in handling the given VisitableSchemaType
  82. // object. In the simplest case, this function can always return an array
  83. // containing a single visitor object, without even looking at the type or
  84. // methodName parameters. In other cases, this function might sometimes
  85. // return an empty array to indicate there are no visitors that should be
  86. // applied to the given VisitableSchemaType object. For an example of a
  87. // visitor pattern that benefits from this abstraction, see the
  88. // SchemaDirectiveVisitor class below.
  89. visitorSelector) {
  90. // Helper function that calls visitorSelector and applies the resulting
  91. // visitors to the given type, with arguments [type, ...args].
  92. function callMethod(methodName, type) {
  93. var args = [];
  94. for (var _i = 2; _i < arguments.length; _i++) {
  95. args[_i - 2] = arguments[_i];
  96. }
  97. visitorSelector(type, methodName).every(function (visitor) {
  98. var newType = visitor[methodName].apply(visitor, __spreadArrays([type], args));
  99. if (typeof newType === 'undefined') {
  100. // Keep going without modifying type.
  101. return true;
  102. }
  103. if (methodName === 'visitSchema' ||
  104. type instanceof graphql_1.GraphQLSchema) {
  105. throw new Error("Method " + methodName + " cannot replace schema with " + newType);
  106. }
  107. if (newType === null) {
  108. // Stop the loop and return null form callMethod, which will cause
  109. // the type to be removed from the schema.
  110. type = null;
  111. return false;
  112. }
  113. // Update type to the new type returned by the visitor method, so that
  114. // later directives will see the new type, and callMethod will return
  115. // the final type.
  116. type = newType;
  117. return true;
  118. });
  119. // If there were no directives for this type object, or if all visitor
  120. // methods returned nothing, type will be returned unmodified.
  121. return type;
  122. }
  123. // Recursive helper function that calls any appropriate visitor methods for
  124. // each object in the schema, then traverses the object's children (if any).
  125. function visit(type) {
  126. if (type instanceof graphql_1.GraphQLSchema) {
  127. // Unlike the other types, the root GraphQLSchema object cannot be
  128. // replaced by visitor methods, because that would make life very hard
  129. // for SchemaVisitor subclasses that rely on the original schema object.
  130. callMethod('visitSchema', type);
  131. updateEachKey(type.getTypeMap(), function (namedType, typeName) {
  132. if (!typeName.startsWith('__')) {
  133. // Call visit recursively to let it determine which concrete
  134. // subclass of GraphQLNamedType we found in the type map. Because
  135. // we're using updateEachKey, the result of visit(namedType) may
  136. // cause the type to be removed or replaced.
  137. return visit(namedType);
  138. }
  139. });
  140. return type;
  141. }
  142. if (type instanceof graphql_1.GraphQLObjectType) {
  143. // Note that callMethod('visitObject', type) may not actually call any
  144. // methods, if there are no @directive annotations associated with this
  145. // type, or if this SchemaDirectiveVisitor subclass does not override
  146. // the visitObject method.
  147. var newObject = callMethod('visitObject', type);
  148. if (newObject) {
  149. visitFields(newObject);
  150. }
  151. return newObject;
  152. }
  153. if (type instanceof graphql_1.GraphQLInterfaceType) {
  154. var newInterface = callMethod('visitInterface', type);
  155. if (newInterface) {
  156. visitFields(newInterface);
  157. }
  158. return newInterface;
  159. }
  160. if (type instanceof graphql_1.GraphQLInputObjectType) {
  161. var newInputObject_1 = callMethod('visitInputObject', type);
  162. if (newInputObject_1) {
  163. updateEachKey(newInputObject_1.getFields(), function (field) {
  164. // Since we call a different method for input object fields, we
  165. // can't reuse the visitFields function here.
  166. return callMethod('visitInputFieldDefinition', field, {
  167. objectType: newInputObject_1,
  168. });
  169. });
  170. }
  171. return newInputObject_1;
  172. }
  173. if (type instanceof graphql_1.GraphQLScalarType) {
  174. return callMethod('visitScalar', type);
  175. }
  176. if (type instanceof graphql_1.GraphQLUnionType) {
  177. return callMethod('visitUnion', type);
  178. }
  179. if (type instanceof graphql_1.GraphQLEnumType) {
  180. var newEnum_1 = callMethod('visitEnum', type);
  181. if (newEnum_1) {
  182. updateEachKey(newEnum_1.getValues(), function (value) {
  183. return callMethod('visitEnumValue', value, {
  184. enumType: newEnum_1,
  185. });
  186. });
  187. }
  188. return newEnum_1;
  189. }
  190. throw new Error("Unexpected schema type: " + type);
  191. }
  192. function visitFields(type) {
  193. updateEachKey(type.getFields(), function (field) {
  194. // It would be nice if we could call visit(field) recursively here, but
  195. // GraphQLField is merely a type, not a value that can be detected using
  196. // an instanceof check, so we have to visit the fields in this lexical
  197. // context, so that TypeScript can validate the call to
  198. // visitFieldDefinition.
  199. var newField = callMethod('visitFieldDefinition', field, {
  200. // While any field visitor needs a reference to the field object, some
  201. // field visitors may also need to know the enclosing (parent) type,
  202. // perhaps to determine if the parent is a GraphQLObjectType or a
  203. // GraphQLInterfaceType. To obtain a reference to the parent, a
  204. // visitor method can have a second parameter, which will be an object
  205. // with an .objectType property referring to the parent.
  206. objectType: type,
  207. });
  208. if (newField && newField.args) {
  209. updateEachKey(newField.args, function (arg) {
  210. return callMethod('visitArgumentDefinition', arg, {
  211. // Like visitFieldDefinition, visitArgumentDefinition takes a
  212. // second parameter that provides additional context, namely the
  213. // parent .field and grandparent .objectType. Remember that the
  214. // current GraphQLSchema is always available via this.schema.
  215. field: newField,
  216. objectType: type,
  217. });
  218. });
  219. }
  220. return newField;
  221. });
  222. }
  223. visit(schema);
  224. // Return the original schema for convenience, even though it cannot have
  225. // been replaced or removed by the code above.
  226. return schema;
  227. }
  228. exports.visitSchema = visitSchema;
  229. // Update any references to named schema types that disagree with the named
  230. // types found in schema.getTypeMap().
  231. function healSchema(schema) {
  232. heal(schema);
  233. return schema;
  234. function heal(type) {
  235. if (type instanceof graphql_1.GraphQLSchema) {
  236. var originalTypeMap_1 = type.getTypeMap();
  237. var actualNamedTypeMap_1 = Object.create(null);
  238. // If any of the .name properties of the GraphQLNamedType objects in
  239. // schema.getTypeMap() have changed, the keys of the type map need to
  240. // be updated accordingly.
  241. each(originalTypeMap_1, function (namedType, typeName) {
  242. if (typeName.startsWith('__')) {
  243. return;
  244. }
  245. var actualName = namedType.name;
  246. if (actualName.startsWith('__')) {
  247. return;
  248. }
  249. if (hasOwn.call(actualNamedTypeMap_1, actualName)) {
  250. throw new Error("Duplicate schema type name " + actualName);
  251. }
  252. actualNamedTypeMap_1[actualName] = namedType;
  253. // Note: we are deliberately leaving namedType in the schema by its
  254. // original name (which might be different from actualName), so that
  255. // references by that name can be healed.
  256. });
  257. // Now add back every named type by its actual name.
  258. each(actualNamedTypeMap_1, function (namedType, typeName) {
  259. originalTypeMap_1[typeName] = namedType;
  260. });
  261. // Directive declaration argument types can refer to named types.
  262. each(type.getDirectives(), function (decl) {
  263. if (decl.args) {
  264. each(decl.args, function (arg) {
  265. arg.type = healType(arg.type);
  266. });
  267. }
  268. });
  269. each(originalTypeMap_1, function (namedType, typeName) {
  270. if (!typeName.startsWith('__')) {
  271. heal(namedType);
  272. }
  273. });
  274. updateEachKey(originalTypeMap_1, function (namedType, typeName) {
  275. // Dangling references to renamed types should remain in the schema
  276. // during healing, but must be removed now, so that the following
  277. // invariant holds for all names: schema.getType(name).name === name
  278. if (!typeName.startsWith('__') &&
  279. !hasOwn.call(actualNamedTypeMap_1, typeName)) {
  280. return null;
  281. }
  282. });
  283. }
  284. else if (type instanceof graphql_1.GraphQLObjectType) {
  285. healFields(type);
  286. each(type.getInterfaces(), function (iface) { return heal(iface); });
  287. }
  288. else if (type instanceof graphql_1.GraphQLInterfaceType) {
  289. healFields(type);
  290. }
  291. else if (type instanceof graphql_1.GraphQLInputObjectType) {
  292. each(type.getFields(), function (field) {
  293. field.type = healType(field.type);
  294. });
  295. }
  296. else if (type instanceof graphql_1.GraphQLScalarType) {
  297. // Nothing to do.
  298. }
  299. else if (type instanceof graphql_1.GraphQLUnionType) {
  300. updateEachKey(type.getTypes(), function (t) { return healType(t); });
  301. }
  302. else if (type instanceof graphql_1.GraphQLEnumType) {
  303. // Nothing to do.
  304. }
  305. else {
  306. throw new Error("Unexpected schema type: " + type);
  307. }
  308. }
  309. function healFields(type) {
  310. each(type.getFields(), function (field) {
  311. field.type = healType(field.type);
  312. if (field.args) {
  313. each(field.args, function (arg) {
  314. arg.type = healType(arg.type);
  315. });
  316. }
  317. });
  318. }
  319. function healType(type) {
  320. // Unwrap the two known wrapper types
  321. if (type instanceof graphql_1.GraphQLList) {
  322. type = new graphql_1.GraphQLList(healType(type.ofType));
  323. }
  324. else if (type instanceof graphql_1.GraphQLNonNull) {
  325. type = new graphql_1.GraphQLNonNull(healType(type.ofType));
  326. }
  327. else if (graphql_1.isNamedType(type)) {
  328. // If a type annotation on a field or an argument or a union member is
  329. // any `GraphQLNamedType` with a `name`, then it must end up identical
  330. // to `schema.getType(name)`, since `schema.getTypeMap()` is the source
  331. // of truth for all named schema types.
  332. var namedType = type;
  333. var officialType = schema.getType(namedType.name);
  334. if (officialType && namedType !== officialType) {
  335. return officialType;
  336. }
  337. }
  338. return type;
  339. }
  340. }
  341. exports.healSchema = healSchema;
  342. // This class represents a reusable implementation of a @directive that may
  343. // appear in a GraphQL schema written in Schema Definition Language.
  344. //
  345. // By overriding one or more visit{Object,Union,...} methods, a subclass
  346. // registers interest in certain schema types, such as GraphQLObjectType,
  347. // GraphQLUnionType, etc. When SchemaDirectiveVisitor.visitSchemaDirectives is
  348. // called with a GraphQLSchema object and a map of visitor subclasses, the
  349. // overidden methods of those subclasses allow the visitors to obtain
  350. // references to any type objects that have @directives attached to them,
  351. // enabling visitors to inspect or modify the schema as appropriate.
  352. //
  353. // For example, if a directive called @rest(url: "...") appears after a field
  354. // definition, a SchemaDirectiveVisitor subclass could provide meaning to that
  355. // directive by overriding the visitFieldDefinition method (which receives a
  356. // GraphQLField parameter), and then the body of that visitor method could
  357. // manipulate the field's resolver function to fetch data from a REST endpoint
  358. // described by the url argument passed to the @rest directive:
  359. //
  360. // const typeDefs = `
  361. // type Query {
  362. // people: [Person] @rest(url: "/api/v1/people")
  363. // }`;
  364. //
  365. // const schema = makeExecutableSchema({ typeDefs });
  366. //
  367. // SchemaDirectiveVisitor.visitSchemaDirectives(schema, {
  368. // rest: class extends SchemaDirectiveVisitor {
  369. // public visitFieldDefinition(field: GraphQLField<any, any>) {
  370. // const { url } = this.args;
  371. // field.resolve = () => fetch(url);
  372. // }
  373. // }
  374. // });
  375. //
  376. // The subclass in this example is defined as an anonymous class expression,
  377. // for brevity. A truly reusable SchemaDirectiveVisitor would most likely be
  378. // defined in a library using a named class declaration, and then exported for
  379. // consumption by other modules and packages.
  380. //
  381. // See below for a complete list of overridable visitor methods, their
  382. // parameter types, and more details about the properties exposed by instances
  383. // of the SchemaDirectiveVisitor class.
  384. var SchemaDirectiveVisitor = /** @class */ (function (_super) {
  385. __extends(SchemaDirectiveVisitor, _super);
  386. // Mark the constructor protected to enforce passing SchemaDirectiveVisitor
  387. // subclasses (not instances) to visitSchemaDirectives.
  388. function SchemaDirectiveVisitor(config) {
  389. var _this = _super.call(this) || this;
  390. _this.name = config.name;
  391. _this.args = config.args;
  392. _this.visitedType = config.visitedType;
  393. _this.schema = config.schema;
  394. _this.context = config.context;
  395. return _this;
  396. }
  397. // Override this method to return a custom GraphQLDirective (or modify one
  398. // already present in the schema) to enforce argument types, provide default
  399. // argument values, or specify schema locations where this @directive may
  400. // appear. By default, any declaration found in the schema will be returned.
  401. SchemaDirectiveVisitor.getDirectiveDeclaration = function (directiveName, schema) {
  402. return schema.getDirective(directiveName);
  403. };
  404. // Call SchemaDirectiveVisitor.visitSchemaDirectives to visit every
  405. // @directive in the schema and create an appropriate SchemaDirectiveVisitor
  406. // instance to visit the object decorated by the @directive.
  407. SchemaDirectiveVisitor.visitSchemaDirectives = function (schema, directiveVisitors,
  408. // Optional context object that will be available to all visitor instances
  409. // via this.context. Defaults to an empty null-prototype object.
  410. context) {
  411. if (context === void 0) { context = Object.create(null); }
  412. // If the schema declares any directives for public consumption, record
  413. // them here so that we can properly coerce arguments when/if we encounter
  414. // an occurrence of the directive while walking the schema below.
  415. var declaredDirectives = this.getDeclaredDirectives(schema, directiveVisitors);
  416. // Map from directive names to lists of SchemaDirectiveVisitor instances
  417. // created while visiting the schema.
  418. var createdVisitors = Object.create(null);
  419. Object.keys(directiveVisitors).forEach(function (directiveName) {
  420. createdVisitors[directiveName] = [];
  421. });
  422. function visitorSelector(type, methodName) {
  423. var visitors = [];
  424. var directiveNodes = type.astNode && type.astNode.directives;
  425. if (!directiveNodes) {
  426. return visitors;
  427. }
  428. directiveNodes.forEach(function (directiveNode) {
  429. var directiveName = directiveNode.name.value;
  430. if (!hasOwn.call(directiveVisitors, directiveName)) {
  431. return;
  432. }
  433. var visitorClass = directiveVisitors[directiveName];
  434. // Avoid creating visitor objects if visitorClass does not override
  435. // the visitor method named by methodName.
  436. if (!visitorClass.implementsVisitorMethod(methodName)) {
  437. return;
  438. }
  439. var decl = declaredDirectives[directiveName];
  440. var args;
  441. if (decl) {
  442. // If this directive was explicitly declared, use the declared
  443. // argument types (and any default values) to check, coerce, and/or
  444. // supply default values for the given arguments.
  445. args = values_1.getArgumentValues(decl, directiveNode);
  446. }
  447. else {
  448. // If this directive was not explicitly declared, just convert the
  449. // argument nodes to their corresponding JavaScript values.
  450. args = Object.create(null);
  451. directiveNode.arguments.forEach(function (arg) {
  452. args[arg.name.value] = valueFromASTUntyped(arg.value);
  453. });
  454. }
  455. // As foretold in comments near the top of the visitSchemaDirectives
  456. // method, this is where instances of the SchemaDirectiveVisitor class
  457. // get created and assigned names. While subclasses could override the
  458. // constructor method, the constructor is marked as protected, so
  459. // these are the only arguments that will ever be passed.
  460. visitors.push(new visitorClass({
  461. name: directiveName,
  462. args: args,
  463. visitedType: type,
  464. schema: schema,
  465. context: context,
  466. }));
  467. });
  468. if (visitors.length > 0) {
  469. visitors.forEach(function (visitor) {
  470. createdVisitors[visitor.name].push(visitor);
  471. });
  472. }
  473. return visitors;
  474. }
  475. visitSchema(schema, visitorSelector);
  476. // Automatically update any references to named schema types replaced
  477. // during the traversal, so implementors don't have to worry about that.
  478. healSchema(schema);
  479. return createdVisitors;
  480. };
  481. SchemaDirectiveVisitor.getDeclaredDirectives = function (schema, directiveVisitors) {
  482. var declaredDirectives = Object.create(null);
  483. each(schema.getDirectives(), function (decl) {
  484. declaredDirectives[decl.name] = decl;
  485. });
  486. // If the visitor subclass overrides getDirectiveDeclaration, and it
  487. // returns a non-null GraphQLDirective, use that instead of any directive
  488. // declared in the schema itself. Reasoning: if a SchemaDirectiveVisitor
  489. // goes to the trouble of implementing getDirectiveDeclaration, it should
  490. // be able to rely on that implementation.
  491. each(directiveVisitors, function (visitorClass, directiveName) {
  492. var decl = visitorClass.getDirectiveDeclaration(directiveName, schema);
  493. if (decl) {
  494. declaredDirectives[directiveName] = decl;
  495. }
  496. });
  497. each(declaredDirectives, function (decl, name) {
  498. if (!hasOwn.call(directiveVisitors, name)) {
  499. // SchemaDirectiveVisitors.visitSchemaDirectives might be called
  500. // multiple times with partial directiveVisitors maps, so it's not
  501. // necessarily an error for directiveVisitors to be missing an
  502. // implementation of a directive that was declared in the schema.
  503. return;
  504. }
  505. var visitorClass = directiveVisitors[name];
  506. each(decl.locations, function (loc) {
  507. var visitorMethodName = directiveLocationToVisitorMethodName(loc);
  508. if (SchemaVisitor.implementsVisitorMethod(visitorMethodName) &&
  509. !visitorClass.implementsVisitorMethod(visitorMethodName)) {
  510. // While visitor subclasses may implement extra visitor methods,
  511. // it's definitely a mistake if the GraphQLDirective declares itself
  512. // applicable to certain schema locations, and the visitor subclass
  513. // does not implement all the corresponding methods.
  514. throw new Error("SchemaDirectiveVisitor for @" + name + " must implement " + visitorMethodName + " method");
  515. }
  516. });
  517. });
  518. return declaredDirectives;
  519. };
  520. return SchemaDirectiveVisitor;
  521. }(SchemaVisitor));
  522. exports.SchemaDirectiveVisitor = SchemaDirectiveVisitor;
  523. // Convert a string like "FIELD_DEFINITION" to "visitFieldDefinition".
  524. function directiveLocationToVisitorMethodName(loc) {
  525. return 'visit' + loc.replace(/([^_]*)_?/g, function (wholeMatch, part) {
  526. return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
  527. });
  528. }
  529. function each(arrayOrObject, callback) {
  530. Object.keys(arrayOrObject).forEach(function (key) {
  531. callback(arrayOrObject[key], key);
  532. });
  533. }
  534. // A more powerful version of each that has the ability to replace or remove
  535. // array or object keys.
  536. function updateEachKey(arrayOrObject,
  537. // The callback can return nothing to leave the key untouched, null to remove
  538. // the key from the array or object, or a non-null V to replace the value.
  539. callback) {
  540. var deletedCount = 0;
  541. Object.keys(arrayOrObject).forEach(function (key) {
  542. var result = callback(arrayOrObject[key], key);
  543. if (typeof result === 'undefined') {
  544. return;
  545. }
  546. if (result === null) {
  547. delete arrayOrObject[key];
  548. deletedCount++;
  549. return;
  550. }
  551. arrayOrObject[key] = result;
  552. });
  553. if (deletedCount > 0 && Array.isArray(arrayOrObject)) {
  554. // Remove any holes from the array due to deleted elements.
  555. arrayOrObject.splice(0).forEach(function (elem) {
  556. arrayOrObject.push(elem);
  557. });
  558. }
  559. }
  560. // Similar to the graphql-js function of the same name, slightly simplified:
  561. // https://github.com/graphql/graphql-js/blob/master/src/utilities/valueFromASTUntyped.js
  562. function valueFromASTUntyped(valueNode) {
  563. switch (valueNode.kind) {
  564. case graphql_1.Kind.NULL:
  565. return null;
  566. case graphql_1.Kind.INT:
  567. return parseInt(valueNode.value, 10);
  568. case graphql_1.Kind.FLOAT:
  569. return parseFloat(valueNode.value);
  570. case graphql_1.Kind.STRING:
  571. case graphql_1.Kind.ENUM:
  572. case graphql_1.Kind.BOOLEAN:
  573. return valueNode.value;
  574. case graphql_1.Kind.LIST:
  575. return valueNode.values.map(valueFromASTUntyped);
  576. case graphql_1.Kind.OBJECT:
  577. var obj_1 = Object.create(null);
  578. valueNode.fields.forEach(function (field) {
  579. obj_1[field.name.value] = valueFromASTUntyped(field.value);
  580. });
  581. return obj_1;
  582. /* istanbul ignore next */
  583. default:
  584. throw new Error('Unexpected value kind: ' + valueNode.kind);
  585. }
  586. }
  587. //# sourceMappingURL=schemaVisitor.js.map