|
| 1 | +import { AST } from 'eslint'; |
| 2 | +import { Comment, SourceLocation } from 'estree'; |
| 3 | +import { |
| 4 | + ArgumentNode, |
| 5 | + ASTNode, |
| 6 | + DefinitionNode, |
| 7 | + DirectiveDefinitionNode, |
| 8 | + DirectiveNode, |
| 9 | + DocumentNode, |
| 10 | + EnumTypeDefinitionNode, |
| 11 | + EnumTypeExtensionNode, |
| 12 | + EnumValueDefinitionNode, |
| 13 | + ExecutableDefinitionNode, |
| 14 | + FieldDefinitionNode, |
| 15 | + FieldNode, |
| 16 | + FragmentSpreadNode, |
| 17 | + InlineFragmentNode, |
| 18 | + InputObjectTypeDefinitionNode, |
| 19 | + InputObjectTypeExtensionNode, |
| 20 | + InputValueDefinitionNode, |
| 21 | + InterfaceTypeDefinitionNode, |
| 22 | + InterfaceTypeExtensionNode, |
| 23 | + ListTypeNode, |
| 24 | + NamedTypeNode, |
| 25 | + NameNode, |
| 26 | + NonNullTypeNode, |
| 27 | + ObjectTypeDefinitionNode, |
| 28 | + ObjectTypeExtensionNode, |
| 29 | + OperationTypeDefinitionNode, |
| 30 | + SelectionNode, |
| 31 | + SelectionSetNode, |
| 32 | + TypeDefinitionNode, |
| 33 | + TypeExtensionNode, |
| 34 | + TypeInfo, |
| 35 | + TypeNode, |
| 36 | + VariableDefinitionNode, |
| 37 | + VariableNode |
| 38 | +} from 'graphql'; |
| 39 | + |
| 40 | +type SafeGraphQLType<T extends ASTNode> = T extends { type: TypeNode } |
| 41 | + ? Omit<T, 'loc' | 'type'> & { gqlType: T['type'] } |
| 42 | + : Omit<T, 'loc'>; |
| 43 | + |
| 44 | +type Writeable<T> = { -readonly [K in keyof T]: T[K] }; |
| 45 | + |
| 46 | +export type TypeInformation = { |
| 47 | + argument: ReturnType<TypeInfo['getArgument']>; |
| 48 | + defaultValue: ReturnType<TypeInfo['getDefaultValue']>; |
| 49 | + directive: ReturnType<TypeInfo['getDirective']>; |
| 50 | + enumValue: ReturnType<TypeInfo['getEnumValue']>; |
| 51 | + fieldDef: ReturnType<TypeInfo['getFieldDef']>; |
| 52 | + inputType: ReturnType<TypeInfo['getInputType']>; |
| 53 | + parentInputType: ReturnType<TypeInfo['getParentInputType']>; |
| 54 | + parentType: ReturnType<TypeInfo['getParentType']>; |
| 55 | + gqlType: ReturnType<TypeInfo['getType']>; |
| 56 | +}; |
| 57 | + |
| 58 | +type NodeWithName = |
| 59 | + | ArgumentNode |
| 60 | + | DirectiveDefinitionNode |
| 61 | + | EnumValueDefinitionNode |
| 62 | + | ExecutableDefinitionNode |
| 63 | + | FieldDefinitionNode |
| 64 | + | FieldNode |
| 65 | + | FragmentSpreadNode |
| 66 | + | NamedTypeNode |
| 67 | + | TypeDefinitionNode |
| 68 | + | TypeExtensionNode |
| 69 | + | VariableNode; |
| 70 | + |
| 71 | +type NodeWithType = |
| 72 | + | FieldDefinitionNode |
| 73 | + | InputValueDefinitionNode |
| 74 | + | ListTypeNode |
| 75 | + | NonNullTypeNode |
| 76 | + | OperationTypeDefinitionNode |
| 77 | + | VariableDefinitionNode; |
| 78 | + |
| 79 | +type ParentNode<T> = T extends DocumentNode |
| 80 | + ? AST.Program |
| 81 | + : T extends DefinitionNode |
| 82 | + ? DocumentNode |
| 83 | + : T extends EnumValueDefinitionNode |
| 84 | + ? EnumTypeDefinitionNode | EnumTypeExtensionNode |
| 85 | + : T extends InputValueDefinitionNode |
| 86 | + ? |
| 87 | + | DirectiveDefinitionNode |
| 88 | + | FieldDefinitionNode |
| 89 | + | InputObjectTypeDefinitionNode |
| 90 | + | InputObjectTypeExtensionNode |
| 91 | + : T extends FieldDefinitionNode |
| 92 | + ? |
| 93 | + | InterfaceTypeDefinitionNode |
| 94 | + | InterfaceTypeExtensionNode |
| 95 | + | ObjectTypeDefinitionNode |
| 96 | + | ObjectTypeExtensionNode |
| 97 | + : T extends SelectionSetNode |
| 98 | + ? ExecutableDefinitionNode | FieldNode | InlineFragmentNode |
| 99 | + : T extends SelectionNode |
| 100 | + ? SelectionSetNode |
| 101 | + : T extends TypeNode |
| 102 | + ? NodeWithType |
| 103 | + : T extends NameNode |
| 104 | + ? NodeWithName |
| 105 | + : T extends DirectiveNode |
| 106 | + ? InputObjectTypeDefinitionNode | ObjectTypeDefinitionNode |
| 107 | + : T extends VariableNode |
| 108 | + ? VariableDefinitionNode |
| 109 | + : unknown; // Explicitly show error to add new ternary with parent nodes |
| 110 | + |
| 111 | +type Node<T extends ASTNode, WithTypeInfo extends boolean> = |
| 112 | + // Remove readonly for friendly editor popup |
| 113 | + Writeable<SafeGraphQLType<T>> & { |
| 114 | + type: T['kind']; |
| 115 | + loc: SourceLocation; |
| 116 | + range: AST.Range; |
| 117 | + leadingComments: Comment[]; |
| 118 | + typeInfo: () => WithTypeInfo extends true ? TypeInformation : Record<string, never>; |
| 119 | + rawNode: () => T; |
| 120 | + parent: GraphQLESTreeNode<ParentNode<T>>; |
| 121 | + }; |
| 122 | + |
| 123 | +export type GraphQLESTreeNode<T, W extends boolean = false> = |
| 124 | + // if value is ASTNode => convert to Node type |
| 125 | + T extends ASTNode |
| 126 | + ? { |
| 127 | + // Loop recursively over object values |
| 128 | + [K in keyof Node<T, W>]: Node<T, W>[K] extends |
| 129 | + | ReadonlyArray<infer ArrayItem> |
| 130 | + | undefined // If optional readonly array => loop over array items |
| 131 | + ? GraphQLESTreeNode<ArrayItem, W>[] |
| 132 | + : GraphQLESTreeNode<Node<T, W>[K], W>; |
| 133 | + } |
| 134 | + : // If Program node => add `parent: null` field |
| 135 | + T extends AST.Program |
| 136 | + ? T & { parent: null } |
| 137 | + : // Return value as is |
| 138 | + T; |
0 commit comments