123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- import Maybe from '../tsutils/Maybe';
- import { TypeInfo } from '../utilities/TypeInfo';
- import { ASTNode, ASTKindToNode } from './ast';
- /**
- * A visitor is provided to visit, it contains the collection of
- * relevant functions to be called during the visitor's traversal.
- */
- export type ASTVisitor = Visitor<ASTKindToNode>;
- export type Visitor<KindToNode, Nodes = KindToNode[keyof KindToNode]> =
- | EnterLeaveVisitor<KindToNode, Nodes>
- | ShapeMapVisitor<KindToNode, Nodes>;
- interface EnterLeave<T> {
- readonly enter?: T;
- readonly leave?: T;
- }
- type EnterLeaveVisitor<KindToNode, Nodes> = EnterLeave<
- VisitFn<Nodes> | { [K in keyof KindToNode]?: VisitFn<Nodes, KindToNode[K]> }
- >;
- type ShapeMapVisitor<KindToNode, Nodes> = {
- [K in keyof KindToNode]?:
- | VisitFn<Nodes, KindToNode[K]>
- | EnterLeave<VisitFn<Nodes, KindToNode[K]>>;
- };
- /**
- * A visitor is comprised of visit functions, which are called on each node
- * during the visitor's traversal.
- */
- export type VisitFn<TAnyNode, TVisitedNode = TAnyNode> = (
- /** The current node being visiting.*/
- node: TVisitedNode,
- /** The index or key to this node from the parent node or Array. */
- key: string | number | undefined,
- /** The parent immediately above this node, which may be an Array. */
- parent: TAnyNode | ReadonlyArray<TAnyNode> | undefined,
- /** The key path to get to this node from the root node. */
- path: ReadonlyArray<string | number>,
- /** All nodes and Arrays visited before reaching parent of this node.
- * These correspond to array indices in `path`.
- * Note: ancestors includes arrays which contain the parent of visited node.
- */
- ancestors: ReadonlyArray<TAnyNode | ReadonlyArray<TAnyNode>>,
- ) => any;
- /**
- * A KeyMap describes each the traversable properties of each kind of node.
- */
- export type VisitorKeyMap<T> = { [P in keyof T]: ReadonlyArray<keyof T[P]> };
- // TODO: Should be `[]`, but that requires TypeScript@3
- type EmptyTuple = never[];
- export const QueryDocumentKeys: {
- Name: EmptyTuple;
- Document: ['definitions'];
- // Prettier forces trailing commas, but TS pre 3.2 doesn't allow them.
- // prettier-ignore
- OperationDefinition: [
- 'name',
- 'variableDefinitions',
- 'directives',
- 'selectionSet'
- ];
- VariableDefinition: ['variable', 'type', 'defaultValue', 'directives'];
- Variable: ['name'];
- SelectionSet: ['selections'];
- Field: ['alias', 'name', 'arguments', 'directives', 'selectionSet'];
- Argument: ['name', 'value'];
- FragmentSpread: ['name', 'directives'];
- InlineFragment: ['typeCondition', 'directives', 'selectionSet'];
- // prettier-ignore
- FragmentDefinition: [
- 'name',
- // Note: fragment variable definitions are experimental and may be changed
- // or removed in the future.
- 'variableDefinitions',
- 'typeCondition',
- 'directives',
- 'selectionSet'
- ];
- IntValue: EmptyTuple;
- FloatValue: EmptyTuple;
- StringValue: EmptyTuple;
- BooleanValue: EmptyTuple;
- NullValue: EmptyTuple;
- EnumValue: EmptyTuple;
- ListValue: ['values'];
- ObjectValue: ['fields'];
- ObjectField: ['name', 'value'];
- Directive: ['name', 'arguments'];
- NamedType: ['name'];
- ListType: ['type'];
- NonNullType: ['type'];
- SchemaDefinition: ['directives', 'operationTypes'];
- OperationTypeDefinition: ['type'];
- ScalarTypeDefinition: ['description', 'name', 'directives'];
- // prettier-ignore
- ObjectTypeDefinition: [
- 'description',
- 'name',
- 'interfaces',
- 'directives',
- 'fields'
- ];
- FieldDefinition: ['description', 'name', 'arguments', 'type', 'directives'];
- // prettier-ignore
- InputValueDefinition: [
- 'description',
- 'name',
- 'type',
- 'defaultValue',
- 'directives'
- ];
- InterfaceTypeDefinition: ['description', 'name', 'directives', 'fields'];
- UnionTypeDefinition: ['description', 'name', 'directives', 'types'];
- EnumTypeDefinition: ['description', 'name', 'directives', 'values'];
- EnumValueDefinition: ['description', 'name', 'directives'];
- InputObjectTypeDefinition: ['description', 'name', 'directives', 'fields'];
- DirectiveDefinition: ['description', 'name', 'arguments', 'locations'];
- SchemaExtension: ['directives', 'operationTypes'];
- ScalarTypeExtension: ['name', 'directives'];
- ObjectTypeExtension: ['name', 'interfaces', 'directives', 'fields'];
- InterfaceTypeExtension: ['name', 'directives', 'fields'];
- UnionTypeExtension: ['name', 'directives', 'types'];
- EnumTypeExtension: ['name', 'directives', 'values'];
- InputObjectTypeExtension: ['name', 'directives', 'fields'];
- };
- export const BREAK: any;
- /**
- * visit() will walk through an AST using a depth first traversal, calling
- * the visitor's enter function at each node in the traversal, and calling the
- * leave function after visiting that node and all of its child nodes.
- *
- * By returning different values from the enter and leave functions, the
- * behavior of the visitor can be altered, including skipping over a sub-tree of
- * the AST (by returning false), editing the AST by returning a value or null
- * to remove the value, or to stop the whole traversal by returning BREAK.
- *
- * When using visit() to edit an AST, the original AST will not be modified, and
- * a new version of the AST with the changes applied will be returned from the
- * visit function.
- *
- * const editedAST = visit(ast, {
- * enter(node, key, parent, path, ancestors) {
- * // @return
- * // undefined: no action
- * // false: skip visiting this node
- * // visitor.BREAK: stop visiting altogether
- * // null: delete this node
- * // any value: replace this node with the returned value
- * },
- * leave(node, key, parent, path, ancestors) {
- * // @return
- * // undefined: no action
- * // false: no action
- * // visitor.BREAK: stop visiting altogether
- * // null: delete this node
- * // any value: replace this node with the returned value
- * }
- * });
- *
- * Alternatively to providing enter() and leave() functions, a visitor can
- * instead provide functions named the same as the kinds of AST nodes, or
- * enter/leave visitors at a named key, leading to four permutations of
- * visitor API:
- *
- * 1) Named visitors triggered when entering a node a specific kind.
- *
- * visit(ast, {
- * Kind(node) {
- * // enter the "Kind" node
- * }
- * })
- *
- * 2) Named visitors that trigger upon entering and leaving a node of
- * a specific kind.
- *
- * visit(ast, {
- * Kind: {
- * enter(node) {
- * // enter the "Kind" node
- * }
- * leave(node) {
- * // leave the "Kind" node
- * }
- * }
- * })
- *
- * 3) Generic visitors that trigger upon entering and leaving any node.
- *
- * visit(ast, {
- * enter(node) {
- * // enter any node
- * },
- * leave(node) {
- * // leave any node
- * }
- * })
- *
- * 4) Parallel visitors for entering and leaving nodes of a specific kind.
- *
- * visit(ast, {
- * enter: {
- * Kind(node) {
- * // enter the "Kind" node
- * }
- * },
- * leave: {
- * Kind(node) {
- * // leave the "Kind" node
- * }
- * }
- * })
- */
- export function visit(
- root: ASTNode,
- visitor: Visitor<ASTKindToNode>,
- visitorKeys?: VisitorKeyMap<ASTKindToNode>, // default: QueryDocumentKeys
- ): any;
- /**
- * Creates a new visitor instance which delegates to many visitors to run in
- * parallel. Each visitor will be visited for each node before moving on.
- *
- * If a prior visitor edits a node, no following visitors will see that node.
- */
- export function visitInParallel(
- visitors: ReadonlyArray<Visitor<ASTKindToNode>>,
- ): Visitor<ASTKindToNode>;
- /**
- * Creates a new visitor instance which maintains a provided TypeInfo instance
- * along with visiting visitor.
- */
- export function visitWithTypeInfo(
- typeInfo: TypeInfo,
- visitor: Visitor<ASTKindToNode>,
- ): Visitor<ASTKindToNode>;
- /**
- * Given a visitor instance, if it is leaving or not, and a node kind, return
- * the function the visitor runtime should call.
- */
- export function getVisitFn(
- visitor: Visitor<any>,
- kind: string,
- isLeaving: boolean,
- ): Maybe<VisitFn<any>>;
|