|
4 | 4 | SelectionSetNode, |
5 | 5 | DefinitionNode, |
6 | 6 | Kind, |
| 7 | + DirectiveNode, |
7 | 8 | SelectionNode, |
| 9 | + getArgumentValues, |
8 | 10 | } from 'graphql'; |
9 | 11 | import { FieldWeight, TypeWeightObject, Variables } from '../@types/buildTypeWeights'; |
10 | 12 | /** |
@@ -139,42 +141,70 @@ class ASTParser { |
139 | 141 | } |
140 | 142 | } |
141 | 143 |
|
| 144 | + directiveCheck(directive: DirectiveNode): boolean { |
| 145 | + // let directive; |
| 146 | + // if (directives) [directive] = directives; |
| 147 | + if (directive?.arguments) { |
| 148 | + const argument = directive.arguments[0]; |
| 149 | + const argumentHasVariables = |
| 150 | + argument.value.kind === Kind.VARIABLE && argument.name.value === 'if'; |
| 151 | + |
| 152 | + let directiveArgumentValue; |
| 153 | + if (argument.value.kind === Kind.BOOLEAN) { |
| 154 | + directiveArgumentValue = Boolean(argument.value.value); |
| 155 | + } else if (argumentHasVariables) { |
| 156 | + directiveArgumentValue = Boolean(this.variables[argument.value.name.value]); |
| 157 | + } |
| 158 | + |
| 159 | + return ( |
| 160 | + (directive.name.value === 'include' && directiveArgumentValue === true) || |
| 161 | + (directive.name.value === 'skip' && directiveArgumentValue === false) |
| 162 | + ); |
| 163 | + } |
| 164 | + return true; |
| 165 | + } |
| 166 | + |
142 | 167 | private selectionNode(node: SelectionNode, parentName: string): number { |
143 | 168 | let complexity = 0; |
144 | | - this.depth += 1; |
145 | | - if (this.depth > this.maxDepth) this.maxDepth = this.depth; |
146 | | - // check the kind property against the set of selection nodes that are possible |
147 | | - if (node.kind === Kind.FIELD) { |
148 | | - // call the function that handle field nodes |
149 | | - complexity += this.fieldNode(node, parentName.toLowerCase()); |
150 | | - } else if (node.kind === Kind.FRAGMENT_SPREAD) { |
151 | | - // add complexity and depth from fragment cache |
152 | | - const { complexity: fragComplexity, depth: fragDepth } = |
153 | | - this.fragmentCache[node.name.value]; |
154 | | - complexity += fragComplexity; |
155 | | - this.depth += fragDepth; |
| 169 | + const directive = node.directives; |
| 170 | + if (directive && this.directiveCheck(directive[0])) { |
| 171 | + this.depth += 1; |
156 | 172 | if (this.depth > this.maxDepth) this.maxDepth = this.depth; |
157 | | - this.depth -= fragDepth; |
| 173 | + // check the kind property against the set of selection nodes that are possible |
| 174 | + if (node.kind === Kind.FIELD) { |
| 175 | + // call the function that handle field nodes |
| 176 | + complexity += this.fieldNode(node, parentName.toLowerCase()); |
| 177 | + } else if (node.kind === Kind.FRAGMENT_SPREAD) { |
| 178 | + // add complexity and depth from fragment cache |
| 179 | + const { complexity: fragComplexity, depth: fragDepth } = |
| 180 | + this.fragmentCache[node.name.value]; |
| 181 | + complexity += fragComplexity; |
| 182 | + this.depth += fragDepth; |
| 183 | + if (this.depth > this.maxDepth) this.maxDepth = this.depth; |
| 184 | + this.depth -= fragDepth; |
| 185 | + |
| 186 | + // This is a leaf |
| 187 | + // need to parse fragment definition at root and get the result here |
| 188 | + } else if (node.kind === Kind.INLINE_FRAGMENT) { |
| 189 | + const { typeCondition } = node; |
158 | 190 |
|
159 | | - // This is a leaf |
160 | | - // need to parse fragment definition at root and get the result here |
161 | | - } else if (node.kind === Kind.INLINE_FRAGMENT) { |
162 | | - const { typeCondition } = node; |
| 191 | + // named type is the type from which inner fields should be take |
| 192 | + // If the TypeCondition is omitted, an inline fragment is considered to be of the same type as the enclosing context |
| 193 | + const namedType = typeCondition |
| 194 | + ? typeCondition.name.value.toLowerCase() |
| 195 | + : parentName; |
163 | 196 |
|
164 | | - // named type is the type from which inner fields should be take |
165 | | - // If the TypeCondition is omitted, an inline fragment is considered to be of the same type as the enclosing context |
166 | | - const namedType = typeCondition ? typeCondition.name.value.toLowerCase() : parentName; |
| 197 | + // TODO: Handle directives like @include and @skip |
| 198 | + // subtract 1 before, and add one after, entering the fragment selection to negate the additional level of depth added |
| 199 | + this.depth -= 1; |
| 200 | + complexity += this.selectionSetNode(node.selectionSet, namedType); |
| 201 | + this.depth += 1; |
| 202 | + } else { |
| 203 | + throw new Error(`ERROR: ASTParser.selectionNode: node type not supported`); |
| 204 | + } |
167 | 205 |
|
168 | | - // TODO: Handle directives like @include and @skip |
169 | | - // subtract 1 before, and add one after, entering the fragment selection to negate the additional level of depth added |
170 | 206 | this.depth -= 1; |
171 | | - complexity += this.selectionSetNode(node.selectionSet, namedType); |
172 | | - this.depth += 1; |
173 | | - } else { |
174 | | - throw new Error(`ERROR: ASTParser.selectionNode: node type not supported`); |
175 | 207 | } |
176 | | - |
177 | | - this.depth -= 1; |
178 | 208 | return complexity; |
179 | 209 | } |
180 | 210 |
|
|
0 commit comments