/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow strict * @format */ // flowlint ambiguous-object-type:error 'use strict'; const {visit} = require('graphql'); import type { Argument, ClientExtension, Condition, Defer, Directive, Fragment, FragmentSpread, InlineDataFragmentSpread, InlineFragment, LinkedField, Literal, LocalArgumentDefinition, ModuleImport, Request, Root, RootArgumentDefinition, ScalarField, SplitOperation, Stream, Variable, } from './IR'; const NodeKeys = { Argument: ['value'], ClientExtension: ['selections'], Condition: ['condition', 'selections'], Defer: ['selections', 'if'], Directive: ['args'], Fragment: ['argumentDefinitions', 'directives', 'selections'], FragmentSpread: ['args', 'directives'], InlineDataFragmentSpread: ['selections'], InlineFragment: ['directives', 'selections'], LinkedField: ['args', 'directives', 'selections'], Literal: [], LocalArgumentDefinition: [], ModuleImport: ['selections'], Request: ['fragment', 'root'], Root: ['argumentDefinitions', 'directives', 'selections'], RootArgumentDefinition: [], ScalarField: ['args', 'directives'], SplitOperation: ['selections'], Stream: ['selections', 'if', 'initialCount'], Variable: [], }; export type VisitNode = | Argument | ClientExtension | Condition | Defer | Directive | Fragment | FragmentSpread | InlineDataFragmentSpread | InlineFragment | LinkedField | Literal | LocalArgumentDefinition | ModuleImport | Request | Root | RootArgumentDefinition | ScalarField | SplitOperation | Stream | Variable; type EnterLeave = {|+enter?: T, +leave?: T|}; export type VisitFn = ( node: T, // node we're visiting key?: $FlowFixMe, // index/key to node from parent array/object parent?: ?(VisitNode | Array), // Object immediately above node path?: Array<$FlowFixMe>, // keys to get from root: [keyForChild, ..., keyForParent] ancestors?: Array>, // [root, child1, ..., grandparent] // Note: ancestors includes arrays which contain the visited node // These correspond to array indices in `path`. ) => $FlowFixMe; export type NodeVisitorObject = | EnterLeave> | VisitFn; export type NodeVisitor = | EnterLeave<{| Argument?: VisitFn, ClientExtension?: VisitFn, Condition?: VisitFn, Defer?: VisitFn, Directive?: VisitFn, Fragment?: VisitFn, FragmentSpread?: VisitFn, InlineFragment?: VisitFn, LinkedField?: VisitFn, Literal?: VisitFn, LocalArgumentDefinition?: VisitFn, ModuleImport?: VisitFn, Request?: VisitFn, Root?: VisitFn, RootArgumentDefinition?: VisitFn, ScalarField?: VisitFn, SplitOperation?: VisitFn, Stream?: VisitFn, Variable?: VisitFn, |}> | {| Argument?: NodeVisitorObject, ClientExtension?: VisitFn, Condition?: NodeVisitorObject, Defer?: NodeVisitorObject, Directive?: NodeVisitorObject, Fragment?: NodeVisitorObject, FragmentSpread?: NodeVisitorObject, InlineDataFragmentSpread?: NodeVisitorObject, InlineFragment?: NodeVisitorObject, LinkedField?: NodeVisitorObject, Literal?: NodeVisitorObject, LocalArgumentDefinition?: NodeVisitorObject, ModuleImport?: NodeVisitorObject, Request?: NodeVisitorObject, Root?: NodeVisitorObject, RootArgumentDefinition?: NodeVisitorObject, ScalarField?: NodeVisitorObject, SplitOperation?: NodeVisitorObject, Stream?: NodeVisitorObject, Variable?: NodeVisitorObject, |}; function visitIR(root: VisitNode, visitor: NodeVisitor): $FlowFixMe { return (visit: $FlowFixMe)(root, visitor, NodeKeys); } module.exports = {visit: visitIR};