-
Notifications
You must be signed in to change notification settings - Fork 0
/
getFieldInfo.ts
116 lines (99 loc) · 2.71 KB
/
getFieldInfo.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import {
FieldNode,
FragmentDefinitionNode,
getLocation,
OperationDefinitionNode,
parse,
Source,
TypeInfo,
visit,
visitWithTypeInfo
} from "graphql";
import { GraphQLTag } from "./types";
export interface FieldInfo {
name: string;
line: number;
parentType: string;
type: string;
rootNodeName: string;
filePath: string;
}
function findFields(
graphQLTag: GraphQLTag,
typeInfo: TypeInfo,
cb: (fieldInfo: FieldInfo) => void
) {
const ast = parse(graphQLTag.template);
visit(
ast,
visitWithTypeInfo(typeInfo, {
OperationDefinition(node) {
visitFields(node, graphQLTag, typeInfo, cb);
},
FragmentDefinition(node) {
visitFields(node, graphQLTag, typeInfo, cb);
}
})
);
}
function visitFields(
node: OperationDefinitionNode | FragmentDefinitionNode,
graphQLTag: GraphQLTag,
typeInfo: TypeInfo,
cb: (fieldInfo: FieldInfo) => void
) {
if (!node.name) {
throw new Error(
"visitFields expects OperationDefinitions and FragmentDefinitions to be named"
);
}
const { filePath, sourceLocationOffset, template } = graphQLTag;
const operationOrFragmentName = node.name.value;
visit(
node,
visitWithTypeInfo(typeInfo, {
Field(graphqlNode) {
// Discard client only fields, but don't throw an error
if (isClientOnlyField(graphqlNode)) return;
const parentType = typeInfo.getParentType();
const nodeType = typeInfo.getType();
const nodeName = graphqlNode.name.value;
if (!parentType) {
throw new Error(
`visitFields expects fields to have a parent type. No parent type for ${nodeName}`
);
}
if (!nodeType) {
throw new Error(
`visitFields expects fields to have a type. No type for ${nodeName}`
);
}
if (!graphqlNode.loc) {
throw new Error(
`visitFields expects fields to have a location. No location for ${nodeName}`
);
}
const loc = graphqlNode.loc;
const source = new Source(template);
const templateStart = getLocation(source, loc.start);
const line = sourceLocationOffset.line + templateStart.line - 1;
cb({
name: nodeName,
type: nodeType.toString(),
parentType: parentType.toString(),
rootNodeName: operationOrFragmentName,
filePath,
line
});
}
})
);
}
function isClientOnlyField(field: FieldNode): boolean {
if (!field.directives) return false;
const clientOnlyDirective = field.directives.find(directive => {
return directive.name.value === "client";
});
return !!clientOnlyDirective;
}
export default findFields;