Mirror: The spec-compliant minimum of client-side GraphQL.

fix linting ci (#2)

authored by Jovi De Croock and committed by GitHub 56083bb3 170d61ba

Changed files
+89 -143
benchmark
src
+2 -2
benchmark/suite.js
··· 6 6 const document = graphql.parse(kitchenSink, { noLocation: true }); 7 7 8 8 suite('parse kitchen sink query', () => { 9 - benchmark('0no-co/graphql.web', () => { 9 + benchmark('0no-co/graphql.web', () => { 10 10 graphqlWeb.parse(kitchenSink); 11 11 }); 12 12 ··· 16 16 }); 17 17 18 18 suite('print kitchen sink query', () => { 19 - benchmark('0no-co/graphql.web', () => { 19 + benchmark('0no-co/graphql.web', () => { 20 20 graphqlWeb.print(document); 21 21 }); 22 22
+3 -1
src/__tests__/parser.test.ts
··· 6 6 7 7 describe('print', () => { 8 8 it('prints the kitchen sink document like graphql.js does', () => { 9 - const sink = readFileSync(__dirname + '/../../benchmark/kitchen_sink.graphql', { encoding: 'utf8' }); 9 + const sink = readFileSync(__dirname + '/../../benchmark/kitchen_sink.graphql', { 10 + encoding: 'utf8', 11 + }); 10 12 const doc = parse(sink); 11 13 expect(doc).toMatchSnapshot(); 12 14 expect(doc).toEqual(graphql_parse(sink, { noLocation: true }));
+3 -10
src/ast.ts
··· 52 52 readonly loc?: Location; 53 53 } 54 54 55 - export type DefinitionNode = 56 - | OperationDefinitionNode 57 - | FragmentDefinitionNode; 58 - export type ExecutableDefinitionNode = 59 - | OperationDefinitionNode 60 - | FragmentDefinitionNode; 55 + export type DefinitionNode = OperationDefinitionNode | FragmentDefinitionNode; 56 + export type ExecutableDefinitionNode = OperationDefinitionNode | FragmentDefinitionNode; 61 57 62 58 export interface OperationDefinitionNode { 63 59 readonly kind: Kind.OPERATION_DEFINITION; ··· 92 88 selections: ReadonlyArray<SelectionNode>; 93 89 } 94 90 95 - export declare type SelectionNode = 96 - | FieldNode 97 - | FragmentSpreadNode 98 - | InlineFragmentNode; 91 + export declare type SelectionNode = FieldNode | FragmentSpreadNode | InlineFragmentNode; 99 92 100 93 export interface FieldNode { 101 94 readonly kind: Kind.FIELD;
+1 -1
src/error.ts
··· 17 17 positions?: Maybe<ReadonlyArray<number>>, 18 18 path?: Maybe<ReadonlyArray<string | number>>, 19 19 originalError?: Maybe<Error>, 20 - extensions?: Maybe<Extensions>, 20 + extensions?: Maybe<Extensions> 21 21 ) { 22 22 super(message); 23 23
+38 -63
src/parser.ts
··· 18 18 function advance(pattern: RegExp) { 19 19 pattern.lastIndex = idx; 20 20 if (pattern.test(input)) { 21 - const match = input.slice(idx, idx = pattern.lastIndex); 21 + const match = input.slice(idx, (idx = pattern.lastIndex)); 22 22 return match; 23 23 } 24 24 } ··· 56 56 const nameRe = /[_\w][_\d\w]*/y; 57 57 function name(): ast.NameNode | undefined { 58 58 let match: string | undefined; 59 - if (match = advance(nameRe)) { 59 + if ((match = advance(nameRe))) { 60 60 return { 61 61 kind: Kind.NAME, 62 62 value: match, ··· 81 81 let match: string | undefined; 82 82 if (advance(nullRe)) { 83 83 out = { kind: Kind.NULL }; 84 - } else if (match = advance(boolRe)) { 84 + } else if ((match = advance(boolRe))) { 85 85 out = { 86 86 kind: Kind.BOOLEAN, 87 87 value: match === 'true', ··· 94 94 value: match.slice(1), 95 95 }, 96 96 }; 97 - } else if (match = advance(floatRe)) { 97 + } else if ((match = advance(floatRe))) { 98 98 out = { 99 99 kind: Kind.FLOAT, 100 100 value: match, 101 101 }; 102 - } else if (match = advance(intRe)) { 102 + } else if ((match = advance(intRe))) { 103 103 out = { 104 104 kind: Kind.INT, 105 105 value: match, 106 106 }; 107 - } else if (match = advance(nameRe)) { 107 + } else if ((match = advance(nameRe))) { 108 108 out = { 109 109 kind: Kind.ENUM, 110 110 value: match, 111 111 }; 112 - } else if (match = advance(blockStringRe)) { 112 + } else if ((match = advance(blockStringRe))) { 113 113 out = { 114 114 kind: Kind.STRING, 115 115 value: blockString(match.slice(3, -3)), 116 116 block: true, 117 117 }; 118 - } else if (match = advance(stringRe)) { 118 + } else if ((match = advance(stringRe))) { 119 119 out = { 120 120 kind: Kind.STRING, 121 - value: complexStringRe.test(match) 122 - ? JSON.parse(match) as string 123 - : match.slice(1, -1), 121 + value: complexStringRe.test(match) ? (JSON.parse(match) as string) : match.slice(1, -1), 124 122 block: false, 125 123 }; 126 - } else if (out = list(constant) || object(constant)) { 124 + } else if ((out = list(constant) || object(constant))) { 127 125 return out; 128 126 } 129 127 ··· 137 135 idx++; 138 136 ignored(); 139 137 const values: ast.ValueNode[] = []; 140 - while (match = value(constant)) 141 - values.push(match); 142 - if (input.charCodeAt(idx++) !== 93 /*']'*/) 143 - throw error(Kind.LIST); 138 + while ((match = value(constant))) values.push(match); 139 + if (input.charCodeAt(idx++) !== 93 /*']'*/) throw error(Kind.LIST); 144 140 ignored(); 145 141 return { 146 142 kind: Kind.LIST, ··· 155 151 ignored(); 156 152 const fields: ast.ObjectFieldNode[] = []; 157 153 let _name: ast.NameNode | undefined; 158 - while (_name = name()) { 154 + while ((_name = name())) { 159 155 ignored(); 160 - if (input.charCodeAt(idx++) !== 58 /*':'*/) 161 - throw error(Kind.OBJECT_FIELD); 156 + if (input.charCodeAt(idx++) !== 58 /*':'*/) throw error(Kind.OBJECT_FIELD); 162 157 ignored(); 163 158 const _value = value(constant); 164 - if (!_value) 165 - throw error(Kind.OBJECT_FIELD); 159 + if (!_value) throw error(Kind.OBJECT_FIELD); 166 160 fields.push({ 167 161 kind: Kind.OBJECT_FIELD, 168 162 name: _name, 169 163 value: _value, 170 164 }); 171 165 } 172 - if (input.charCodeAt(idx++) !== 125 /*'}'*/) 173 - throw error(Kind.OBJECT); 166 + if (input.charCodeAt(idx++) !== 125 /*'}'*/) throw error(Kind.OBJECT); 174 167 ignored(); 175 168 return { 176 169 kind: Kind.OBJECT, ··· 186 179 idx++; 187 180 ignored(); 188 181 let _name: ast.NameNode | undefined; 189 - while (_name = name()) { 182 + while ((_name = name())) { 190 183 ignored(); 191 - if (input.charCodeAt(idx++) !== 58 /*':'*/) 192 - throw error(Kind.ARGUMENT); 184 + if (input.charCodeAt(idx++) !== 58 /*':'*/) throw error(Kind.ARGUMENT); 193 185 ignored(); 194 186 const _value = value(constant); 195 - if (!_value) 196 - throw error(Kind.ARGUMENT); 187 + if (!_value) throw error(Kind.ARGUMENT); 197 188 args.push({ 198 189 kind: Kind.ARGUMENT, 199 190 name: _name, 200 191 value: _value, 201 192 }); 202 193 } 203 - if (!args.length || input.charCodeAt(idx++) !== 41 /*')'*/) 204 - throw error(Kind.ARGUMENT); 194 + if (!args.length || input.charCodeAt(idx++) !== 41 /*')'*/) throw error(Kind.ARGUMENT); 205 195 ignored(); 206 196 } 207 197 return args; ··· 216 206 while (input.charCodeAt(idx) === 64 /*'@'*/) { 217 207 idx++; 218 208 const _name = name(); 219 - if (!_name) 220 - throw error(Kind.DIRECTIVE); 209 + if (!_name) throw error(Kind.DIRECTIVE); 221 210 ignored(); 222 211 directives.push({ 223 212 kind: Kind.DIRECTIVE, ··· 239 228 ignored(); 240 229 _alias = _name; 241 230 _name = name(); 242 - if (!_name) 243 - throw error(Kind.FIELD); 231 + if (!_name) throw error(Kind.FIELD); 244 232 ignored(); 245 233 } 246 234 return { ··· 261 249 idx++; 262 250 ignored(); 263 251 const _type = type(); 264 - if (!_type || input.charCodeAt(idx++) !== 93 /*']'*/) 265 - throw error(Kind.LIST_TYPE); 252 + if (!_type || input.charCodeAt(idx++) !== 93 /*']'*/) throw error(Kind.LIST_TYPE); 266 253 match = { 267 254 kind: Kind.LIST_TYPE, 268 255 type: _type, 269 256 }; 270 - } else if (match = name()) { 257 + } else if ((match = name())) { 271 258 match = { 272 259 kind: Kind.NAMED_TYPE, 273 260 name: match, ··· 294 281 if (advance(typeConditionRe)) { 295 282 ignored(); 296 283 const _name = name(); 297 - if (!_name) 298 - throw error(Kind.NAMED_TYPE); 284 + if (!_name) throw error(Kind.NAMED_TYPE); 299 285 ignored(); 300 286 return { 301 287 kind: Kind.NAMED_TYPE, ··· 323 309 const _typeCondition = typeCondition(); 324 310 const _directives = directives(false); 325 311 const _selectionSet = selectionSet(); 326 - if (!_selectionSet) 327 - throw error(Kind.INLINE_FRAGMENT); 312 + if (!_selectionSet) throw error(Kind.INLINE_FRAGMENT); 328 313 return { 329 314 kind: Kind.INLINE_FRAGMENT, 330 315 typeCondition: _typeCondition, ··· 342 327 idx++; 343 328 ignored(); 344 329 const selections: ast.SelectionNode[] = []; 345 - while (match = fragmentSpread() || field()) 346 - selections.push(match); 330 + while ((match = fragmentSpread() || field())) selections.push(match); 347 331 if (!selections.length || input.charCodeAt(idx++) !== 125 /*'}'*/) 348 332 throw error(Kind.SELECTION_SET); 349 333 ignored(); ··· 361 345 if (input.charCodeAt(idx) === 40 /*'('*/) { 362 346 idx++; 363 347 ignored(); 364 - while (match = advance(variableRe)) { 348 + while ((match = advance(variableRe))) { 365 349 ignored(); 366 - if (input.charCodeAt(idx++) !== 58 /*':'*/) 367 - throw error(Kind.VARIABLE_DEFINITION); 350 + if (input.charCodeAt(idx++) !== 58 /*':'*/) throw error(Kind.VARIABLE_DEFINITION); 368 351 const _type = type(); 369 - if (!_type) 370 - throw error(Kind.VARIABLE_DEFINITION); 352 + if (!_type) throw error(Kind.VARIABLE_DEFINITION); 371 353 let _defaultValue: ast.ValueNode | undefined; 372 354 if (input.charCodeAt(idx) === 61 /*'='*/) { 373 355 idx++; 374 356 ignored(); 375 357 _defaultValue = value(true); 376 - if (!_defaultValue) 377 - throw error(Kind.VARIABLE_DEFINITION); 358 + if (!_defaultValue) throw error(Kind.VARIABLE_DEFINITION); 378 359 } 379 360 ignored(); 380 361 vars.push({ ··· 391 372 directives: directives(true), 392 373 }); 393 374 } 394 - if (input.charCodeAt(idx++) !== 41 /*')'*/) 395 - throw error(Kind.VARIABLE_DEFINITION); 375 + if (input.charCodeAt(idx++) !== 41 /*')'*/) throw error(Kind.VARIABLE_DEFINITION); 396 376 ignored(); 397 377 } 398 378 return vars; ··· 403 383 if (advance(fragmentDefinitionRe)) { 404 384 ignored(); 405 385 const _name = name(); 406 - if (!_name) 407 - throw error(Kind.FRAGMENT_DEFINITION); 386 + if (!_name) throw error(Kind.FRAGMENT_DEFINITION); 408 387 ignored(); 409 388 const _typeCondition = typeCondition(); 410 - if (!_typeCondition) 411 - throw error(Kind.FRAGMENT_DEFINITION); 389 + if (!_typeCondition) throw error(Kind.FRAGMENT_DEFINITION); 412 390 const _directives = directives(false); 413 391 const _selectionSet = selectionSet(); 414 - if (!_selectionSet) 415 - throw error(Kind.FRAGMENT_DEFINITION); 392 + if (!_selectionSet) throw error(Kind.FRAGMENT_DEFINITION); 416 393 return { 417 394 kind: Kind.FRAGMENT_DEFINITION, 418 395 name: _name, ··· 429 406 let _name: ast.NameNode | undefined; 430 407 let _variableDefinitions: ast.VariableDefinitionNode[] = []; 431 408 let _directives: ast.DirectiveNode[] = []; 432 - if (_operation = advance(operationDefinitionRe)) { 409 + if ((_operation = advance(operationDefinitionRe))) { 433 410 ignored(); 434 411 _name = name(); 435 412 _variableDefinitions = variableDefinitions(); ··· 452 429 let match: ast.DefinitionNode | void; 453 430 ignored(); 454 431 const definitions: ast.DefinitionNode[] = []; 455 - while (match = fragmentDefinition() || operationDefinition()) 456 - definitions.push(match); 457 - if (idx !== input.length) 458 - throw error(Kind.DOCUMENT); 432 + while ((match = fragmentDefinition() || operationDefinition())) definitions.push(match); 433 + if (idx !== input.length) throw error(Kind.DOCUMENT); 459 434 return { 460 435 kind: Kind.DOCUMENT, 461 436 definitions,
+29 -44
src/printer.ts
··· 9 9 return '"""\n' + string.replace(/"""/g, '\\"""') + '\n"""'; 10 10 } 11 11 12 - const hasItems = <T>( 13 - array: ReadonlyArray<T> | undefined | null 14 - ): array is ReadonlyArray<T> => !!(array && array.length); 12 + const hasItems = <T>(array: ReadonlyArray<T> | undefined | null): array is ReadonlyArray<T> => 13 + !!(array && array.length); 15 14 16 15 const MAX_LINE_LENGTH = 80; 17 16 ··· 19 18 let out: string; 20 19 switch (node.kind) { 21 20 case Kind.OPERATION_DEFINITION: 22 - if (node.operation === 'query' && !node.name && !hasItems(node.variableDefinitions) && !hasItems(node.directives)) { 21 + if ( 22 + node.operation === 'query' && 23 + !node.name && 24 + !hasItems(node.variableDefinitions) && 25 + !hasItems(node.directives) 26 + ) { 23 27 return print(node.selectionSet); 24 28 } 25 29 out = node.operation; 26 - if (node.name) 27 - out += ' ' + node.name.value; 30 + if (node.name) out += ' ' + node.name.value; 28 31 if (hasItems(node.variableDefinitions)) { 29 32 if (!node.name) out += ' '; 30 33 out += '(' + node.variableDefinitions.map(print).join(', ') + ')'; 31 34 } 32 - if (hasItems(node.directives)) 33 - out += ' ' + node.directives.map(print).join(' '); 35 + if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 34 36 return out + ' ' + print(node.selectionSet); 35 37 36 38 case Kind.VARIABLE_DEFINITION: 37 - out = print(node.variable) + 38 - ': ' + 39 - print(node.type); 40 - if (node.defaultValue) 41 - out += ' = ' + print(node.defaultValue); 42 - if (hasItems(node.directives)) 43 - out += ' ' + node.directives.map(print).join(' '); 39 + out = print(node.variable) + ': ' + print(node.type); 40 + if (node.defaultValue) out += ' = ' + print(node.defaultValue); 41 + if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 44 42 return out; 45 43 46 44 case Kind.FIELD: 47 - out = (node.alias ? print(node.alias) + ': ' : '') + node.name.value 45 + out = (node.alias ? print(node.alias) + ': ' : '') + node.name.value; 48 46 if (hasItems(node.arguments)) { 49 47 const args = node.arguments.map(print); 50 48 const argsLine = out + '(' + args.join(', ') + ')'; 51 - out = argsLine.length > MAX_LINE_LENGTH 52 - ? out + '(\n ' + args.join('\n').replace(/\n/g, '\n ') + '\n)' 53 - : argsLine; 49 + out = 50 + argsLine.length > MAX_LINE_LENGTH 51 + ? out + '(\n ' + args.join('\n').replace(/\n/g, '\n ') + '\n)' 52 + : argsLine; 54 53 } 55 - if (hasItems(node.directives)) 56 - out += ' ' + node.directives.map(print).join(' '); 57 - return node.selectionSet 58 - ? out + ' ' + print(node.selectionSet) 59 - : out; 54 + if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 55 + return node.selectionSet ? out + ' ' + print(node.selectionSet) : out; 60 56 61 57 case Kind.STRING: 62 - return node.block 63 - ? printBlockString(node.value) 64 - : printString(node.value); 58 + return node.block ? printBlockString(node.value) : printString(node.value); 65 59 66 60 case Kind.BOOLEAN: 67 61 return '' + node.value; ··· 88 82 return '$' + node.name.value; 89 83 90 84 case Kind.DOCUMENT: 91 - return hasItems(node.definitions) 92 - ? node.definitions.map(print).join('\n\n') 93 - : ''; 85 + return hasItems(node.definitions) ? node.definitions.map(print).join('\n\n') : ''; 94 86 95 87 case Kind.SELECTION_SET: 96 - return '{\n ' + 97 - node.selections.map(print).join('\n').replace(/\n/g, '\n ') + 98 - '\n}'; 88 + return '{\n ' + node.selections.map(print).join('\n').replace(/\n/g, '\n ') + '\n}'; 99 89 100 90 case Kind.ARGUMENT: 101 91 return node.name.value + ': ' + print(node.value); 102 92 103 93 case Kind.FRAGMENT_SPREAD: 104 94 out = '...' + node.name.value; 105 - if (hasItems(node.directives)) 106 - out += ' ' + node.directives.map(print).join(' '); 95 + if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 107 96 return out; 108 97 109 98 case Kind.INLINE_FRAGMENT: 110 99 out = '...'; 111 - if (node.typeCondition) 112 - out += ' on ' + node.typeCondition.name.value; 113 - if (hasItems(node.directives)) 114 - out += ' ' + node.directives.map(print).join(' '); 100 + if (node.typeCondition) out += ' on ' + node.typeCondition.name.value; 101 + if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 115 102 return out + ' ' + print(node.selectionSet); 116 103 117 104 case Kind.FRAGMENT_DEFINITION: 118 105 out = 'fragment ' + node.name.value; 119 106 out += ' on ' + node.typeCondition.name.value; 120 - if (hasItems(node.directives)) 121 - out += ' ' + node.directives.map(print).join(' '); 107 + if (hasItems(node.directives)) out += ' ' + node.directives.map(print).join(' '); 122 108 return out + ' ' + print(node.selectionSet); 123 - 109 + 124 110 case Kind.DIRECTIVE: 125 111 out = '@' + node.name.value; 126 - if (hasItems(node.arguments)) 127 - out += '(' + node.arguments.map(print).join(', ') + ')'; 112 + if (hasItems(node.arguments)) out += '(' + node.arguments.map(print).join(', ') + ')'; 128 113 return out; 129 114 130 115 case Kind.NAMED_TYPE:
+5 -10
src/values.ts
··· 4 4 5 5 export function valueFromASTUntyped( 6 6 node: ValueNode, 7 - variables?: Maybe<Record<string, any>>, 7 + variables?: Maybe<Record<string, any>> 8 8 ): unknown { 9 9 switch (node.kind) { 10 10 case Kind.NULL: ··· 19 19 return node.value; 20 20 case Kind.LIST: { 21 21 const values: unknown[] = []; 22 - for (const value of node.values) 23 - values.push(valueFromASTUntyped(value, variables)); 22 + for (const value of node.values) values.push(valueFromASTUntyped(value, variables)); 24 23 return values; 25 24 } 26 25 case Kind.OBJECT: { ··· 37 36 export function valueFromTypeNode( 38 37 node: ValueNode, 39 38 type: TypeNode, 40 - variables?: Maybe<Record<string, any>>, 39 + variables?: Maybe<Record<string, any>> 41 40 ): unknown { 42 41 if (node.kind === Kind.VARIABLE) { 43 42 const variableName = node.name.value; 44 - return variables 45 - ? valueFromTypeNode(variables[variableName], type, variables) 46 - : undefined; 43 + return variables ? valueFromTypeNode(variables[variableName], type, variables) : undefined; 47 44 } else if (type.kind === Kind.NON_NULL_TYPE) { 48 - return node.kind !== Kind.NULL 49 - ? valueFromTypeNode(node, type, variables) 50 - : undefined 45 + return node.kind !== Kind.NULL ? valueFromTypeNode(node, type, variables) : undefined; 51 46 } else if (node.kind === Kind.NULL) { 52 47 return null; 53 48 } else if (type.kind === Kind.LIST_TYPE) {
+8 -12
src/visitor.ts
··· 6 6 export function visit<R>(root: ASTNode, visitor: ASTReducer<R>): R; 7 7 8 8 export function visit(node: ASTNode, visitor: ASTVisitor | ASTReducer<any>) { 9 - const ancestors: Array<ASTNode | ReadonlyArray<ASTNode>>= []; 9 + const ancestors: Array<ASTNode | ReadonlyArray<ASTNode>> = []; 10 10 const path: Array<string | number> = []; 11 11 12 12 function traverse( 13 13 node: ASTNode, 14 14 key?: string | number | undefined, 15 - parent?: ASTNode | ReadonlyArray<ASTNode> | undefined, 15 + parent?: ASTNode | ReadonlyArray<ASTNode> | undefined 16 16 ) { 17 17 let hasEdited = false; 18 18 19 - const enter = visitor[node.kind] && visitor[node.kind].enter || visitor[node.kind]; 20 - const resultEnter = 21 - enter && enter.call(visitor, node, key, parent, path, ancestors); 19 + const enter = (visitor[node.kind] && visitor[node.kind].enter) || visitor[node.kind]; 20 + const resultEnter = enter && enter.call(visitor, node, key, parent, path, ancestors); 22 21 if (resultEnter === false) { 23 22 return node; 24 23 } else if (resultEnter === null) { ··· 71 70 72 71 if (parent) ancestors.pop(); 73 72 const leave = visitor[node.kind] && visitor[node.kind].leave; 74 - const resultLeave = 75 - leave && leave.call(visitor, node, key, parent, path, ancestors); 73 + const resultLeave = leave && leave.call(visitor, node, key, parent, path, ancestors); 76 74 if (resultLeave === BREAK) { 77 75 throw BREAK; 78 76 } else if (resultLeave !== undefined) { ··· 96 94 export type ASTVisitor = EnterLeaveVisitor<ASTNode> | KindVisitor; 97 95 98 96 type KindVisitor = { 99 - readonly [NodeT in ASTNode as NodeT['kind']]?: 100 - | ASTVisitFn<NodeT> 101 - | EnterLeaveVisitor<NodeT>; 97 + readonly [NodeT in ASTNode as NodeT['kind']]?: ASTVisitFn<NodeT> | EnterLeaveVisitor<NodeT>; 102 98 }; 103 99 104 100 interface EnterLeaveVisitor<TVisitedNode extends ASTNode> { ··· 111 107 key: string | number | undefined, 112 108 parent: ASTNode | ReadonlyArray<ASTNode> | undefined, 113 109 path: ReadonlyArray<string | number>, 114 - ancestors: ReadonlyArray<ASTNode | ReadonlyArray<ASTNode>>, 110 + ancestors: ReadonlyArray<ASTNode | ReadonlyArray<ASTNode>> 115 111 ) => any; 116 112 117 113 export type ASTReducer<R> = { ··· 126 122 key: string | number | undefined, 127 123 parent: ASTNode | ReadonlyArray<ASTNode> | undefined, 128 124 path: ReadonlyArray<string | number>, 129 - ancestors: ReadonlyArray<ASTNode | ReadonlyArray<ASTNode>>, 125 + ancestors: ReadonlyArray<ASTNode | ReadonlyArray<ASTNode>> 130 126 ) => R; 131 127 132 128 type ReducedField<T, R> = T extends null | undefined