@apollo/federation-internals 2.4.0-alpha.1 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.operationToDocument = exports.parseSelectionSet = exports.parseOperation = exports.operationFromDocument = exports.FragmentSelection = exports.FieldSelection = exports.selectionOfElement = exports.selectionSetOfElement = exports.allFieldDefinitionsInSelectionSet = exports.SelectionSet = exports.NamedFragments = exports.NamedFragmentDefinition = exports.selectionSetOf = exports.Operation = exports.concatOperationPaths = exports.conditionalDirectivesInOperationPath = exports.sameOperationPaths = exports.operationPathToStringPath = exports.FragmentElement = exports.Field = void 0;
3
+ exports.operationToDocument = exports.parseSelectionSet = exports.parseOperation = exports.operationFromDocument = exports.FragmentSelection = exports.FieldSelection = exports.selectionOfElement = exports.selectionSetOfElement = exports.selectionSetOf = exports.allFieldDefinitionsInSelectionSet = exports.MutableSelectionSet = exports.SelectionSetUpdates = exports.SelectionSet = exports.NamedFragments = exports.NamedFragmentDefinition = exports.Operation = exports.concatOperationPaths = exports.conditionalDirectivesInOperationPath = exports.sameOperationPaths = exports.operationPathToStringPath = exports.FragmentElement = exports.Field = void 0;
4
4
  const graphql_1 = require("graphql");
5
5
  const definitions_1 = require("./definitions");
6
+ const federation_1 = require("./federation");
6
7
  const error_1 = require("./error");
7
8
  const types_1 = require("./types");
8
9
  const utils_1 = require("./utils");
9
10
  const values_1 = require("./values");
11
+ const uuid_1 = require("uuid");
10
12
  function validate(condition, message, sourceAST) {
11
13
  if (!condition) {
12
14
  throw error_1.ERRORS.INVALID_GRAPHQL.err(message(), { nodes: sourceAST });
@@ -16,12 +18,12 @@ function haveSameDirectives(op1, op2) {
16
18
  return (0, definitions_1.sameDirectiveApplications)(op1.appliedDirectives, op2.appliedDirectives);
17
19
  }
18
20
  class AbstractOperationElement extends definitions_1.DirectiveTargetElement {
19
- constructor(schema, variablesInElement) {
20
- super(schema);
21
- this.variablesInElement = variablesInElement;
21
+ constructor(schema, directives) {
22
+ super(schema, directives);
22
23
  }
23
- variables() {
24
- return (0, definitions_1.mergeVariables)(this.variablesInElement, this.variablesInAppliedDirectives());
24
+ collectVariables(collector) {
25
+ this.collectVariablesInElement(collector);
26
+ this.collectVariablesInAppliedDirectives(collector);
25
27
  }
26
28
  addAttachement(key, value) {
27
29
  if (!this.attachements) {
@@ -42,44 +44,76 @@ class AbstractOperationElement extends definitions_1.DirectiveTargetElement {
42
44
  }
43
45
  }
44
46
  class Field extends AbstractOperationElement {
45
- constructor(definition, args = Object.create(null), variableDefinitions = new definitions_1.VariableDefinitions(), alias) {
46
- super(definition.schema(), (0, definitions_1.variablesInArguments)(args));
47
+ constructor(definition, args, directives, alias) {
48
+ super(definition.schema(), directives);
47
49
  this.definition = definition;
48
50
  this.args = args;
49
- this.variableDefinitions = variableDefinitions;
50
51
  this.alias = alias;
51
52
  this.kind = 'Field';
52
53
  }
54
+ collectVariablesInElement(collector) {
55
+ if (this.args) {
56
+ collector.collectInArguments(this.args);
57
+ }
58
+ }
53
59
  get name() {
54
60
  return this.definition.name;
55
61
  }
62
+ argumentValue(name) {
63
+ return this.args ? this.args[name] : undefined;
64
+ }
56
65
  responseName() {
57
66
  return this.alias ? this.alias : this.name;
58
67
  }
68
+ key() {
69
+ return this.responseName();
70
+ }
71
+ asPathElement() {
72
+ return this.responseName();
73
+ }
59
74
  get parentType() {
60
75
  return this.definition.parent;
61
76
  }
77
+ isLeafField() {
78
+ return (0, definitions_1.isLeafType)((0, definitions_1.baseType)(this.definition.type));
79
+ }
62
80
  withUpdatedDefinition(newDefinition) {
63
- const newField = new Field(newDefinition, this.args, this.variableDefinitions, this.alias);
64
- for (const directive of this.appliedDirectives) {
65
- newField.applyDirective(directive.definition, directive.arguments());
66
- }
81
+ const newField = new Field(newDefinition, this.args, this.appliedDirectives, this.alias);
67
82
  this.copyAttachementsTo(newField);
68
83
  return newField;
69
84
  }
70
85
  withUpdatedAlias(newAlias) {
71
- const newField = new Field(this.definition, this.args, this.variableDefinitions, newAlias);
72
- for (const directive of this.appliedDirectives) {
73
- newField.applyDirective(directive.definition, directive.arguments());
74
- }
86
+ const newField = new Field(this.definition, this.args, this.appliedDirectives, newAlias);
75
87
  this.copyAttachementsTo(newField);
76
88
  return newField;
77
89
  }
90
+ withUpdatedDirectives(newDirectives) {
91
+ const newField = new Field(this.definition, this.args, newDirectives, this.alias);
92
+ this.copyAttachementsTo(newField);
93
+ return newField;
94
+ }
95
+ argumentsToNodes() {
96
+ if (!this.args) {
97
+ return undefined;
98
+ }
99
+ const entries = Object.entries(this.args);
100
+ if (entries.length === 0) {
101
+ return undefined;
102
+ }
103
+ return entries.map(([n, v]) => {
104
+ return {
105
+ kind: graphql_1.Kind.ARGUMENT,
106
+ name: { kind: graphql_1.Kind.NAME, value: n },
107
+ value: (0, values_1.valueToAST)(v, this.definition.argument(n).type),
108
+ };
109
+ });
110
+ }
78
111
  appliesTo(type) {
79
112
  const definition = type.field(this.name);
80
113
  return !!definition && this.selects(definition);
81
114
  }
82
- selects(definition, assumeValid = false) {
115
+ selects(definition, assumeValid = false, variableDefinitions) {
116
+ (0, utils_1.assert)(assumeValid || variableDefinitions, 'Must provide variable definitions if validation is needed');
83
117
  if (definition === this.definition) {
84
118
  return true;
85
119
  }
@@ -87,19 +121,19 @@ class Field extends AbstractOperationElement {
87
121
  return false;
88
122
  }
89
123
  for (const argDef of definition.arguments()) {
90
- const appliedValue = this.args[argDef.name];
124
+ const appliedValue = this.argumentValue(argDef.name);
91
125
  if (appliedValue === undefined) {
92
126
  if (argDef.defaultValue === undefined && !(0, definitions_1.isNullableType)(argDef.type)) {
93
127
  return false;
94
128
  }
95
129
  }
96
130
  else {
97
- if (!assumeValid && !(0, values_1.isValidValue)(appliedValue, argDef, this.variableDefinitions)) {
131
+ if (!assumeValid && !(0, values_1.isValidValue)(appliedValue, argDef, variableDefinitions)) {
98
132
  return false;
99
133
  }
100
134
  }
101
135
  }
102
- if (!assumeValid) {
136
+ if (!assumeValid && this.args) {
103
137
  for (const [name, value] of Object.entries(this.args)) {
104
138
  if (value !== null && definition.argument(name) === undefined) {
105
139
  return false;
@@ -108,39 +142,41 @@ class Field extends AbstractOperationElement {
108
142
  }
109
143
  return true;
110
144
  }
111
- validate() {
145
+ validate(variableDefinitions) {
112
146
  validate(this.name === this.definition.name, () => `Field name "${this.name}" cannot select field "${this.definition.coordinate}: name mismatch"`);
113
147
  for (const argDef of this.definition.arguments()) {
114
- const appliedValue = this.args[argDef.name];
148
+ const appliedValue = this.argumentValue(argDef.name);
115
149
  if (appliedValue === undefined) {
116
150
  validate(argDef.defaultValue !== undefined || (0, definitions_1.isNullableType)(argDef.type), () => `Missing mandatory value for argument "${argDef.name}" of field "${this.definition.coordinate}" in selection "${this}"`);
117
151
  }
118
152
  else {
119
- validate((0, values_1.isValidValue)(appliedValue, argDef, this.variableDefinitions), () => `Invalid value ${(0, values_1.valueToString)(appliedValue)} for argument "${argDef.coordinate}" of type ${argDef.type}`);
153
+ validate((0, values_1.isValidValue)(appliedValue, argDef, variableDefinitions), () => `Invalid value ${(0, values_1.valueToString)(appliedValue)} for argument "${argDef.coordinate}" of type ${argDef.type}`);
120
154
  }
121
155
  }
122
- for (const [name, value] of Object.entries(this.args)) {
123
- validate(value === null || this.definition.argument(name) !== undefined, () => `Unknown argument "${name}" in field application of "${this.name}"`);
156
+ if (this.args) {
157
+ for (const [name, value] of Object.entries(this.args)) {
158
+ validate(value === null || this.definition.argument(name) !== undefined, () => `Unknown argument "${name}" in field application of "${this.name}"`);
159
+ }
124
160
  }
125
161
  }
126
- updateForAddingTo(selectionSet) {
127
- const selectionParent = selectionSet.parentType;
162
+ rebaseOn(parentType) {
128
163
  const fieldParent = this.definition.parent;
129
- if (selectionParent === fieldParent) {
164
+ if (parentType === fieldParent) {
130
165
  return this;
131
166
  }
132
167
  if (this.name === definitions_1.typenameFieldName) {
133
- return this.withUpdatedDefinition(selectionParent.typenameField());
168
+ return this.withUpdatedDefinition(parentType.typenameField());
134
169
  }
135
- validate(this.canRebaseOn(selectionParent), () => `Cannot add selection of field "${this.definition.coordinate}" to selection set of parent type "${selectionParent}"`);
136
- const fieldDef = selectionParent.field(this.name);
137
- validate(fieldDef, () => `Cannot add selection of field "${this.definition.coordinate}" to selection set of parent type "${selectionParent}" (that does not declare that field)`);
170
+ validate(this.canRebaseOn(parentType), () => `Cannot add selection of field "${this.definition.coordinate}" to selection set of parent type "${parentType}"`);
171
+ const fieldDef = parentType.field(this.name);
172
+ validate(fieldDef, () => `Cannot add selection of field "${this.definition.coordinate}" to selection set of parent type "${parentType}" (that does not declare that field)`);
138
173
  return this.withUpdatedDefinition(fieldDef);
139
174
  }
140
175
  canRebaseOn(parentType) {
141
176
  const fieldParentType = this.definition.parent;
142
177
  return parentType.name === fieldParentType.name
143
- || ((0, definitions_1.isInterfaceType)(fieldParentType) && fieldParentType.allImplementations().some(i => i.name === parentType.name));
178
+ || (0, definitions_1.isInterfaceType)(fieldParentType)
179
+ || (0, federation_1.isInterfaceObjectType)(fieldParentType);
144
180
  }
145
181
  typeIfAddedTo(parentType) {
146
182
  var _a, _b;
@@ -171,34 +207,56 @@ class Field extends AbstractOperationElement {
171
207
  return that.kind === 'Field'
172
208
  && this.name === that.name
173
209
  && this.alias === that.alias
174
- && (0, values_1.argumentsEquals)(this.args, that.args)
210
+ && (this.args ? that.args && (0, values_1.argumentsEquals)(this.args, that.args) : !that.args)
175
211
  && haveSameDirectives(this, that);
176
212
  }
177
213
  toString() {
178
214
  const alias = this.alias ? this.alias + ': ' : '';
179
- const entries = Object.entries(this.args);
180
- const args = entries.length == 0
215
+ const entries = this.args ? Object.entries(this.args) : [];
216
+ const args = entries.length === 0
181
217
  ? ''
182
218
  : '(' + entries.map(([n, v]) => { var _a; return `${n}: ${(0, values_1.valueToString)(v, (_a = this.definition.argument(n)) === null || _a === void 0 ? void 0 : _a.type)}`; }).join(', ') + ')';
183
219
  return alias + this.name + args + this.appliedDirectivesToString();
184
220
  }
185
221
  }
186
222
  exports.Field = Field;
223
+ function keyForDirective(directive, directivesNeverEqualToThemselves = ['defer']) {
224
+ if (directivesNeverEqualToThemselves.includes(directive.name)) {
225
+ return (0, uuid_1.v1)();
226
+ }
227
+ const entries = Object.entries(directive.arguments()).filter(([_, v]) => v !== undefined);
228
+ entries.sort(([n1], [n2]) => n1.localeCompare(n2));
229
+ const args = entries.length == 0 ? '' : '(' + entries.map(([n, v]) => `${n}: ${(0, values_1.valueToString)(v, directive.argumentType(n))}`).join(', ') + ')';
230
+ return `@${directive.name}${args}`;
231
+ }
187
232
  class FragmentElement extends AbstractOperationElement {
188
- constructor(sourceType, typeCondition) {
189
- super(sourceType.schema(), []);
233
+ constructor(sourceType, typeCondition, directives) {
234
+ super(sourceType.schema(), directives);
190
235
  this.sourceType = sourceType;
191
236
  this.kind = 'FragmentElement';
192
237
  this.typeCondition = typeCondition !== undefined && typeof typeCondition === 'string'
193
238
  ? this.schema().type(typeCondition)
194
239
  : typeCondition;
195
240
  }
241
+ collectVariablesInElement(_) {
242
+ }
196
243
  get parentType() {
197
244
  return this.sourceType;
198
245
  }
246
+ key() {
247
+ if (!this.computedKey) {
248
+ const keyForDirectives = this.appliedDirectives.map((d) => keyForDirective(d)).join(' ');
249
+ this.computedKey = '...' + (this.typeCondition ? ' on ' + this.typeCondition.name : '') + keyForDirectives;
250
+ }
251
+ return this.computedKey;
252
+ }
199
253
  castedType() {
200
254
  return this.typeCondition ? this.typeCondition : this.sourceType;
201
255
  }
256
+ asPathElement() {
257
+ const condition = this.typeCondition;
258
+ return condition ? `... on ${condition}` : undefined;
259
+ }
202
260
  withUpdatedSourceType(newSourceType) {
203
261
  return this.withUpdatedTypes(newSourceType, this.typeCondition);
204
262
  }
@@ -206,23 +264,24 @@ class FragmentElement extends AbstractOperationElement {
206
264
  return this.withUpdatedTypes(this.sourceType, newCondition);
207
265
  }
208
266
  withUpdatedTypes(newSourceType, newCondition) {
209
- const newFragment = new FragmentElement(newSourceType, newCondition === null || newCondition === void 0 ? void 0 : newCondition.name);
210
- for (const directive of this.appliedDirectives) {
211
- newFragment.applyDirective(directive.definition, directive.arguments());
212
- }
267
+ const newFragment = new FragmentElement(newSourceType, newCondition === null || newCondition === void 0 ? void 0 : newCondition.name, this.appliedDirectives);
268
+ this.copyAttachementsTo(newFragment);
269
+ return newFragment;
270
+ }
271
+ withUpdatedDirectives(newDirectives) {
272
+ const newFragment = new FragmentElement(this.sourceType, this.typeCondition, newDirectives);
213
273
  this.copyAttachementsTo(newFragment);
214
274
  return newFragment;
215
275
  }
216
- updateForAddingTo(selectionSet) {
217
- const selectionParent = selectionSet.parentType;
276
+ rebaseOn(parentType) {
218
277
  const fragmentParent = this.parentType;
219
278
  const typeCondition = this.typeCondition;
220
- if (selectionParent === fragmentParent) {
279
+ if (parentType === fragmentParent) {
221
280
  return this;
222
281
  }
223
- const { canRebase, rebasedCondition } = this.canRebaseOn(selectionParent);
224
- validate(canRebase, () => `Cannot add fragment of condition "${typeCondition}" (runtimes: [${(0, definitions_1.possibleRuntimeTypes)(typeCondition)}]) to selection set of parent type "${selectionParent}" (runtimes: ${(0, definitions_1.possibleRuntimeTypes)(selectionParent)})`);
225
- return this.withUpdatedTypes(selectionParent, rebasedCondition);
282
+ const { canRebase, rebasedCondition } = this.canRebaseOn(parentType);
283
+ validate(canRebase, () => `Cannot add fragment of condition "${typeCondition}" (runtimes: [${(0, definitions_1.possibleRuntimeTypes)(typeCondition)}]) to parent type "${parentType}" (runtimes: ${(0, definitions_1.possibleRuntimeTypes)(parentType)})`);
284
+ return this.withUpdatedTypes(parentType, rebasedCondition);
226
285
  }
227
286
  canRebaseOn(parentType) {
228
287
  if (!this.typeCondition) {
@@ -260,9 +319,8 @@ class FragmentElement extends AbstractOperationElement {
260
319
  if (updatedDirectives.length === this.appliedDirectives.length) {
261
320
  return this;
262
321
  }
263
- const updated = new FragmentElement(this.sourceType, this.typeCondition);
322
+ const updated = new FragmentElement(this.sourceType, this.typeCondition, updatedDirectives);
264
323
  this.copyAttachementsTo(updated);
265
- updatedDirectives.forEach((d) => updated.applyDirective(d.definition, d.arguments()));
266
324
  return updated;
267
325
  }
268
326
  withNormalizedDefer(normalizer) {
@@ -307,11 +365,12 @@ class FragmentElement extends AbstractOperationElement {
307
365
  if (!newDeferArgs) {
308
366
  return this;
309
367
  }
310
- const updated = new FragmentElement(this.sourceType, this.typeCondition);
311
- this.copyAttachementsTo(updated);
312
368
  const deferDirective = this.schema().deferDirective();
313
- this.appliedDirectives.filter((d) => d.name !== deferDirective.name).forEach((d) => updated.applyDirective(d.definition, d.arguments()));
314
- updated.applyDirective(this.schema().deferDirective(), newDeferArgs);
369
+ const updatedDirectives = this.appliedDirectives
370
+ .filter((d) => d.name !== deferDirective.name)
371
+ .concat(new definitions_1.Directive(deferDirective.name, newDeferArgs));
372
+ const updated = new FragmentElement(this.sourceType, this.typeCondition, updatedDirectives);
373
+ this.copyAttachementsTo(updated);
315
374
  return updated;
316
375
  }
317
376
  equals(that) {
@@ -389,6 +448,7 @@ class Operation {
389
448
  this.name = name;
390
449
  }
391
450
  optimize(fragments, minUsagesToOptimize = 2) {
451
+ var _a;
392
452
  (0, utils_1.assert)(minUsagesToOptimize >= 1, `Expected 'minUsagesToOptimize' to be at least 1, but got ${minUsagesToOptimize}`);
393
453
  if (!fragments || fragments.isEmpty()) {
394
454
  return this;
@@ -405,16 +465,24 @@ class Operation {
405
465
  }
406
466
  }
407
467
  const toDeoptimize = (0, utils_1.mapEntries)(usages).filter(([_, count]) => count < minUsagesToOptimize).map(([name]) => name);
408
- optimizedSelection = optimizedSelection.expandFragments(toDeoptimize);
468
+ const newFragments = (_a = optimizedSelection.fragments) === null || _a === void 0 ? void 0 : _a.without(toDeoptimize);
469
+ optimizedSelection = optimizedSelection.expandFragments(toDeoptimize, newFragments);
409
470
  return new Operation(this.schema, this.rootKind, optimizedSelection, this.variableDefinitions, this.name);
410
471
  }
411
472
  expandAllFragments() {
412
- const expandedSelections = this.selectionSet.expandFragments();
473
+ const expandedSelections = this.selectionSet.expandAllFragments();
413
474
  if (expandedSelections === this.selectionSet) {
414
475
  return this;
415
476
  }
416
477
  return new Operation(this.schema, this.rootKind, expandedSelections, this.variableDefinitions, this.name);
417
478
  }
479
+ trimUnsatisfiableBranches() {
480
+ const trimmedSelections = this.selectionSet.trimUnsatisfiableBranches(this.selectionSet.parentType);
481
+ if (trimmedSelections === this.selectionSet) {
482
+ return this;
483
+ }
484
+ return new Operation(this.schema, this.rootKind, trimmedSelections, this.variableDefinitions, this.name);
485
+ }
418
486
  withoutDefer(labelsToRemove) {
419
487
  (0, utils_1.assert)(!this.selectionSet.fragments || this.selectionSet.fragments.isEmpty(), 'Removing @defer currently only work on "expanded" selections (no named fragments)');
420
488
  const updated = this.selectionSet.withoutDefer(labelsToRemove);
@@ -452,35 +520,23 @@ class Operation {
452
520
  }
453
521
  }
454
522
  exports.Operation = Operation;
455
- function addDirectiveNodesToElement(directiveNodes, element) {
456
- if (!directiveNodes) {
457
- return;
458
- }
459
- const schema = element.schema();
460
- for (const node of directiveNodes) {
461
- const directiveDef = schema.directive(node.name.value);
462
- validate(directiveDef, () => `Unknown directive "@${node.name.value}" in selection`);
463
- element.applyDirective(directiveDef, (0, values_1.argumentsFromAST)(directiveDef.coordinate, node.arguments, directiveDef));
464
- }
465
- }
466
- function selectionSetOf(parentType, selection) {
467
- const selectionSet = new SelectionSet(parentType);
468
- selectionSet.add(selection);
469
- return selectionSet;
470
- }
471
- exports.selectionSetOf = selectionSetOf;
472
523
  class NamedFragmentDefinition extends definitions_1.DirectiveTargetElement {
473
- constructor(schema, name, typeCondition, selectionSet) {
474
- super(schema);
524
+ constructor(schema, name, typeCondition, directives) {
525
+ super(schema, directives);
475
526
  this.name = name;
476
527
  this.typeCondition = typeCondition;
477
- this.selectionSet = selectionSet;
478
528
  }
479
- withUpdatedSelectionSet(newSelectionSet) {
480
- return new NamedFragmentDefinition(this.schema(), this.name, this.typeCondition, newSelectionSet);
529
+ setSelectionSet(selectionSet) {
530
+ (0, utils_1.assert)(!this._selectionSet, 'Attempting to set the selection set of a fragment definition already built');
531
+ this._selectionSet = selectionSet;
532
+ return this;
481
533
  }
482
- variables() {
483
- return (0, definitions_1.mergeVariables)(this.variablesInAppliedDirectives(), this.selectionSet.usedVariables());
534
+ get selectionSet() {
535
+ (0, utils_1.assert)(this._selectionSet, () => `Trying to access fragment definition ${this.name} before it is fully built`);
536
+ return this._selectionSet;
537
+ }
538
+ withUpdatedSelectionSet(newSelectionSet) {
539
+ return new NamedFragmentDefinition(this.schema(), this.name, this.typeCondition).setSelectionSet(newSelectionSet);
484
540
  }
485
541
  collectUsedFragmentNames(collector) {
486
542
  this.selectionSet.collectUsedFragmentNames(collector);
@@ -503,8 +559,7 @@ class NamedFragmentDefinition extends definitions_1.DirectiveTargetElement {
503
559
  };
504
560
  }
505
561
  canApplyAtType(type) {
506
- const applyAtType = (0, types_1.sameType)(this.typeCondition, type)
507
- || ((0, definitions_1.isAbstractType)(this.typeCondition) && !(0, definitions_1.isUnionType)(type) && (0, types_1.isDirectSubtype)(this.typeCondition, type));
562
+ const applyAtType = (0, types_1.sameType)(type, this.typeCondition) || (0, definitions_1.runtimeTypesIntersects)(type, this.typeCondition);
508
563
  return applyAtType
509
564
  && this.validForSchema(type.schema());
510
565
  }
@@ -517,8 +572,7 @@ class NamedFragmentDefinition extends definitions_1.DirectiveTargetElement {
517
572
  return false;
518
573
  }
519
574
  try {
520
- const rebasedSelection = new SelectionSet(typeInSchema);
521
- rebasedSelection.mergeIn(this.selectionSet);
575
+ this.selectionSet.rebaseOn(typeInSchema);
522
576
  return true;
523
577
  }
524
578
  catch (e) {
@@ -537,13 +591,6 @@ class NamedFragments {
537
591
  isEmpty() {
538
592
  return this.fragments.size === 0;
539
593
  }
540
- variables() {
541
- let variables = [];
542
- for (const fragment of this.fragments.values()) {
543
- variables = (0, definitions_1.mergeVariables)(variables, fragment.variables());
544
- }
545
- return variables;
546
- }
547
594
  names() {
548
595
  return this.fragments.keys();
549
596
  }
@@ -568,14 +615,14 @@ class NamedFragments {
568
615
  const newFragments = new NamedFragments();
569
616
  for (const fragment of this.fragments.values()) {
570
617
  if (!names.includes(fragment.name)) {
571
- const updatedSelection = fragment.selectionSet.expandFragments(names, false);
572
- const newFragment = updatedSelection === fragment.selectionSet
618
+ const updatedSelectionSet = fragment.selectionSet.expandFragments(names, newFragments);
619
+ const newFragment = updatedSelectionSet === fragment.selectionSet
573
620
  ? fragment
574
- : new NamedFragmentDefinition(fragment.schema(), fragment.name, fragment.typeCondition, updatedSelection);
621
+ : fragment.withUpdatedSelectionSet(updatedSelectionSet);
575
622
  newFragments.add(newFragment);
576
623
  }
577
624
  }
578
- return newFragments;
625
+ return newFragments.isEmpty() ? undefined : newFragments;
579
626
  }
580
627
  get(name) {
581
628
  return this.fragments.get(name);
@@ -586,9 +633,16 @@ class NamedFragments {
586
633
  definitions() {
587
634
  return this.fragments.values();
588
635
  }
589
- validate() {
636
+ map(mapper) {
637
+ const mapped = new NamedFragments();
638
+ for (const def of this.fragments.values()) {
639
+ mapped.fragments.set(def.name, mapper(def));
640
+ }
641
+ return mapped;
642
+ }
643
+ validate(variableDefinitions) {
590
644
  for (const fragment of this.fragments.values()) {
591
- fragment.selectionSet.validate();
645
+ fragment.selectionSet.validate(variableDefinitions);
592
646
  }
593
647
  }
594
648
  toFragmentDefinitionNodes() {
@@ -599,24 +653,6 @@ class NamedFragments {
599
653
  }
600
654
  }
601
655
  exports.NamedFragments = NamedFragments;
602
- class Freezable {
603
- constructor() {
604
- this._isFrozen = false;
605
- }
606
- freeze() {
607
- if (!this.isFrozen()) {
608
- this.freezeInternals();
609
- this._isFrozen = true;
610
- }
611
- return this.us();
612
- }
613
- isFrozen() {
614
- return this._isFrozen;
615
- }
616
- cloneIfFrozen() {
617
- return this.isFrozen() ? this.clone() : this.us();
618
- }
619
- }
620
656
  class DeferNormalizer {
621
657
  constructor() {
622
658
  this.index = 0;
@@ -631,7 +667,7 @@ class DeferNormalizer {
631
667
  while (stack.length > 0) {
632
668
  const selection = stack.pop();
633
669
  if (selection.kind === 'FragmentSelection') {
634
- const deferArgs = selection.element().deferDirectiveArgs();
670
+ const deferArgs = selection.element.deferDirectiveArgs();
635
671
  if (deferArgs) {
636
672
  hasDefers = true;
637
673
  if (!deferArgs.label || deferArgs.if !== undefined) {
@@ -663,132 +699,103 @@ class DeferNormalizer {
663
699
  this.deferConditions.add(condition.name, label);
664
700
  }
665
701
  }
666
- class SelectionSet extends Freezable {
667
- constructor(parentType, fragments) {
668
- super();
702
+ class SelectionSet {
703
+ constructor(parentType, keyedSelections = new Map(), fragments) {
669
704
  this.parentType = parentType;
670
705
  this.fragments = fragments;
671
- this._selections = new utils_1.MultiMap();
672
- this._selectionCount = 0;
673
- validate(!(0, definitions_1.isLeafType)(parentType), () => `Cannot have selection on non-leaf type ${parentType}`);
706
+ this._keyedSelections = keyedSelections;
707
+ this._selections = (0, utils_1.mapValues)(keyedSelections);
674
708
  }
675
- us() {
676
- return this;
677
- }
678
- selections(reversedOrder = false) {
679
- if (!this._cachedSelections) {
680
- const selections = new Array(this._selectionCount);
681
- let idx = 0;
682
- for (const byResponseName of this._selections.values()) {
683
- for (const selection of byResponseName) {
684
- selections[idx++] = selection;
685
- }
686
- }
687
- this._cachedSelections = selections;
709
+ selectionsInReverseOrder() {
710
+ const length = this._selections.length;
711
+ const reversed = new Array(length);
712
+ for (let i = 0; i < length; i++) {
713
+ reversed[i] = this._selections[length - i - 1];
688
714
  }
689
- (0, utils_1.assert)(this._cachedSelections, 'Cache should have been populated');
690
- if (reversedOrder && this._cachedSelections.length > 1) {
691
- const reversed = new Array(this._selectionCount);
692
- for (let i = 0; i < this._selectionCount; i++) {
693
- reversed[i] = this._cachedSelections[this._selectionCount - i - 1];
694
- }
695
- return reversed;
696
- }
697
- return this._cachedSelections;
715
+ return reversed;
716
+ }
717
+ selections() {
718
+ return this._selections;
719
+ }
720
+ hasTopLevelTypenameField() {
721
+ return this._keyedSelections.has(definitions_1.typenameFieldName);
698
722
  }
699
723
  fieldsInSet() {
700
724
  const fields = new Array();
701
725
  for (const selection of this.selections()) {
702
726
  if (selection.kind === 'FieldSelection') {
703
- fields.push({ path: [], field: selection, directParent: this });
727
+ fields.push({ path: [], field: selection });
704
728
  }
705
729
  else {
706
- const condition = selection.element().typeCondition;
730
+ const condition = selection.element.typeCondition;
707
731
  const header = condition ? [`... on ${condition}`] : [];
708
- for (const { path, field, directParent } of selection.selectionSet.fieldsInSet()) {
709
- fields.push({ path: header.concat(path), field, directParent });
732
+ for (const { path, field } of selection.selectionSet.fieldsInSet()) {
733
+ fields.push({ path: header.concat(path), field });
710
734
  }
711
735
  }
712
736
  }
713
737
  return fields;
714
738
  }
715
739
  usedVariables() {
716
- let variables = [];
717
- for (const byResponseName of this._selections.values()) {
718
- for (const selection of byResponseName) {
719
- variables = (0, definitions_1.mergeVariables)(variables, selection.usedVariables());
720
- }
721
- }
722
- if (this.fragments) {
723
- variables = (0, definitions_1.mergeVariables)(variables, this.fragments.variables());
740
+ const collector = new definitions_1.VariableCollector();
741
+ this.collectVariables(collector);
742
+ return collector.variables();
743
+ }
744
+ collectVariables(collector) {
745
+ for (const selection of this.selections()) {
746
+ selection.collectVariables(collector);
724
747
  }
725
- return variables;
726
748
  }
727
749
  collectUsedFragmentNames(collector) {
728
- for (const byResponseName of this._selections.values()) {
729
- for (const selection of byResponseName) {
730
- selection.collectUsedFragmentNames(collector);
731
- }
750
+ for (const selection of this.selections()) {
751
+ selection.collectUsedFragmentNames(collector);
732
752
  }
733
753
  }
734
754
  optimize(fragments) {
735
755
  if (!fragments || fragments.isEmpty()) {
736
756
  return this;
737
757
  }
738
- if (this.fragments && this.fragments.definitions().some(def => fragments.get(def.name))) {
739
- return this;
740
- }
741
- const optimized = new SelectionSet(this.parentType, fragments);
742
- for (const selection of this.selections()) {
743
- optimized.add(selection.optimize(fragments));
744
- }
745
- return optimized;
758
+ (0, utils_1.assert)(!this.fragments || this.fragments.isEmpty(), `Should not be called on selection that already has named fragments, but got ${this.fragments}`);
759
+ return this.lazyMap((selection) => selection.optimize(fragments), { fragments });
746
760
  }
747
- expandFragments(names, updateSelectionSetFragments = true) {
748
- var _a;
749
- if (names && names.length === 0) {
761
+ expandAllFragments() {
762
+ return this.lazyMap((selection) => selection.expandAllFragments(), { fragments: null });
763
+ }
764
+ expandFragments(names, updatedFragments) {
765
+ if (names.length === 0) {
750
766
  return this;
751
767
  }
752
- const newFragments = updateSelectionSetFragments
753
- ? (names ? (_a = this.fragments) === null || _a === void 0 ? void 0 : _a.without(names) : undefined)
754
- : this.fragments;
755
- const withExpanded = new SelectionSet(this.parentType, newFragments);
756
- for (const selection of this.selections()) {
757
- const expanded = selection.expandFragments(names, updateSelectionSetFragments);
758
- if (Array.isArray(expanded)) {
759
- withExpanded.addAll(expanded);
760
- }
761
- else {
762
- withExpanded.add(expanded);
763
- }
764
- }
765
- return withExpanded;
768
+ return this.lazyMap((selection) => selection.expandFragments(names, updatedFragments), { fragments: updatedFragments !== null && updatedFragments !== void 0 ? updatedFragments : null });
766
769
  }
767
- lazyMap(mapper) {
768
- let updatedSelections = undefined;
770
+ trimUnsatisfiableBranches(parentType) {
771
+ return this.lazyMap((selection) => selection.trimUnsatisfiableBranches(parentType), { parentType });
772
+ }
773
+ lazyMap(mapper, options) {
774
+ var _a;
769
775
  const selections = this.selections();
776
+ const updatedFragments = options === null || options === void 0 ? void 0 : options.fragments;
777
+ const newFragments = updatedFragments === undefined ? this.fragments : (updatedFragments !== null && updatedFragments !== void 0 ? updatedFragments : undefined);
778
+ let updatedSelections = undefined;
770
779
  for (let i = 0; i < selections.length; i++) {
771
780
  const selection = selections[i];
772
781
  const updated = mapper(selection);
773
782
  if (updated !== selection && !updatedSelections) {
774
- updatedSelections = [];
783
+ updatedSelections = new SelectionSetUpdates();
775
784
  for (let j = 0; j < i; j++) {
776
- updatedSelections.push(selections[j]);
785
+ updatedSelections.add(selections[j]);
777
786
  }
778
787
  }
779
788
  if (!!updated && updatedSelections) {
780
- if (updated instanceof SelectionSet) {
781
- updated.selections().forEach((s) => updatedSelections.push(s));
782
- }
783
- else {
784
- updatedSelections.push(updated);
785
- }
789
+ updatedSelections.add(updated);
786
790
  }
787
791
  }
788
792
  if (!updatedSelections) {
789
- return this;
793
+ return this.withUpdatedFragments(newFragments);
790
794
  }
791
- return new SelectionSet(this.parentType, this.fragments).addAll(updatedSelections);
795
+ return updatedSelections.toSelectionSet((_a = options === null || options === void 0 ? void 0 : options.parentType) !== null && _a !== void 0 ? _a : this.parentType, newFragments);
796
+ }
797
+ withUpdatedFragments(newFragments) {
798
+ return this.fragments === newFragments ? this : new SelectionSet(this.parentType, this._keyedSelections, newFragments);
792
799
  }
793
800
  withoutDefer(labelsToRemove) {
794
801
  (0, utils_1.assert)(!this.fragments, 'Not yet supported');
@@ -798,6 +805,9 @@ class SelectionSet extends Freezable {
798
805
  (0, utils_1.assert)(!this.fragments, 'Not yet supported');
799
806
  return this.lazyMap((selection) => selection.withNormalizedDefer(normalizer));
800
807
  }
808
+ hasDefer() {
809
+ return this.selections().some((s) => s.hasDefer());
810
+ }
801
811
  filter(predicate) {
802
812
  return this.lazyMap((selection) => selection.filter(predicate));
803
813
  }
@@ -805,169 +815,108 @@ class SelectionSet extends Freezable {
805
815
  const updated = this.filter((selection) => { var _a; return ((_a = selection.selectionSet) === null || _a === void 0 ? void 0 : _a.isEmpty()) !== true; });
806
816
  return updated.isEmpty() ? undefined : updated;
807
817
  }
808
- freezeInternals() {
809
- for (const selection of this.selections()) {
810
- selection.freeze();
811
- }
812
- }
813
- mergeIn(selectionSet) {
814
- for (const selection of selectionSet.selections()) {
815
- this.add(selection);
816
- }
817
- }
818
- addAll(selections) {
819
- selections.forEach(s => this.add(s));
820
- return this;
821
- }
822
- add(selection) {
823
- (0, utils_1.assert)(!this.isFrozen(), () => `Cannot add to frozen selection: ${this}`);
824
- const toAdd = selection.updateForAddingTo(this);
825
- const key = toAdd.key();
826
- const existing = this._selections.get(key);
827
- if (existing) {
828
- for (const existingSelection of existing) {
829
- if (existingSelection.kind === toAdd.kind && haveSameDirectives(existingSelection.element(), toAdd.element())) {
830
- if (toAdd.selectionSet) {
831
- existingSelection.selectionSet.mergeIn(toAdd.selectionSet);
832
- }
833
- return existingSelection;
834
- }
835
- }
836
- }
837
- this._selections.add(key, toAdd);
838
- ++this._selectionCount;
839
- this._cachedSelections = undefined;
840
- return toAdd;
841
- }
842
- removeTopLevelField(responseName) {
843
- (0, utils_1.assert)(!this.isFrozen(), () => `Cannot remove from frozen selection: ${this}`);
844
- const wasRemoved = this._selections.delete(responseName);
845
- if (wasRemoved) {
846
- --this._selectionCount;
847
- this._cachedSelections = undefined;
848
- }
849
- return wasRemoved;
850
- }
851
- addPath(path, onPathEnd) {
852
- let previousSelections = this;
853
- let currentSelections = this;
854
- for (const element of path) {
855
- validate(currentSelections, () => `Cannot apply selection ${element} to non-selectable parent type "${previousSelections.parentType}"`);
856
- const mergedSelection = currentSelections.add(selectionOfElement(element));
857
- previousSelections = currentSelections;
858
- currentSelections = mergedSelection.selectionSet;
859
- }
860
- if (onPathEnd) {
861
- onPathEnd(currentSelections);
862
- }
863
- }
864
- addSelectionSetNode(node, variableDefinitions, fieldAccessor = (type, name) => type.field(name)) {
865
- if (!node) {
866
- return;
867
- }
868
- for (const selectionNode of node.selections) {
869
- this.addSelectionNode(selectionNode, variableDefinitions, fieldAccessor);
818
+ rebaseOn(parentType) {
819
+ if (this.parentType === parentType) {
820
+ return this;
870
821
  }
871
- }
872
- addSelectionNode(node, variableDefinitions, fieldAccessor = (type, name) => type.field(name)) {
873
- this.add(this.nodeToSelection(node, variableDefinitions, fieldAccessor));
874
- }
875
- nodeToSelection(node, variableDefinitions, fieldAccessor) {
876
- var _a, _b;
877
- let selection;
878
- switch (node.kind) {
879
- case graphql_1.Kind.FIELD:
880
- const definition = fieldAccessor(this.parentType, node.name.value);
881
- validate(definition, () => `Cannot query field "${node.name.value}" on type "${this.parentType}".`, this.parentType.sourceAST);
882
- const type = (0, definitions_1.baseType)(definition.type);
883
- selection = new FieldSelection(new Field(definition, (0, values_1.argumentsFromAST)(definition.coordinate, node.arguments, definition), variableDefinitions, (_a = node.alias) === null || _a === void 0 ? void 0 : _a.value), (0, definitions_1.isLeafType)(type) ? undefined : new SelectionSet(type, this.fragments));
884
- if (node.selectionSet) {
885
- validate(selection.selectionSet, () => `Unexpected selection set on leaf field "${selection.element()}"`, selection.element().definition.sourceAST);
886
- selection.selectionSet.addSelectionSetNode(node.selectionSet, variableDefinitions, fieldAccessor);
887
- }
888
- break;
889
- case graphql_1.Kind.INLINE_FRAGMENT:
890
- const element = new FragmentElement(this.parentType, (_b = node.typeCondition) === null || _b === void 0 ? void 0 : _b.name.value);
891
- selection = new InlineFragmentSelection(element, new SelectionSet(element.typeCondition ? element.typeCondition : element.parentType, this.fragments));
892
- selection.selectionSet.addSelectionSetNode(node.selectionSet, variableDefinitions, fieldAccessor);
893
- break;
894
- case graphql_1.Kind.FRAGMENT_SPREAD:
895
- const fragmentName = node.name.value;
896
- validate(this.fragments, () => `Cannot find fragment name "${fragmentName}" (no fragments were provided)`);
897
- selection = new FragmentSpreadSelection(this.parentType, this.fragments, fragmentName);
898
- break;
822
+ const newSelections = new Map();
823
+ for (const selection of this.selections()) {
824
+ newSelections.set(selection.key(), selection.rebaseOn(parentType));
899
825
  }
900
- addDirectiveNodesToElement(node.directives, selection.element());
901
- return selection;
826
+ return new SelectionSet(parentType, newSelections, this.fragments);
902
827
  }
903
828
  equals(that) {
904
829
  if (this === that) {
905
830
  return true;
906
831
  }
907
- if (this._selections.size !== that._selections.size) {
832
+ if (this._selections.length !== that._selections.length) {
908
833
  return false;
909
834
  }
910
- for (const [key, thisSelections] of this._selections) {
911
- const thatSelections = that._selections.get(key);
912
- if (!thatSelections
913
- || thisSelections.length !== thatSelections.length
914
- || !thisSelections.every(thisSelection => thatSelections.some(thatSelection => thisSelection.equals(thatSelection)))) {
835
+ for (const [key, thisSelection] of this._keyedSelections) {
836
+ const thatSelection = that._keyedSelections.get(key);
837
+ if (!thatSelection || !thisSelection.equals(thatSelection)) {
915
838
  return false;
916
839
  }
917
840
  }
918
841
  return true;
919
842
  }
920
- contains(that) {
921
- if (this._selections.size < that._selections.size) {
922
- return false;
843
+ triviallyNestedSelectionsForKey(parentType, key) {
844
+ const found = [];
845
+ for (const selection of this.selections()) {
846
+ if (selection.isUnecessaryInlineFragment(parentType)) {
847
+ const selectionForKey = selection.selectionSet._keyedSelections.get(key);
848
+ if (selectionForKey) {
849
+ found.push(selectionForKey);
850
+ }
851
+ for (const nestedSelection of selection.selectionSet.triviallyNestedSelectionsForKey(parentType, key)) {
852
+ found.push(nestedSelection);
853
+ }
854
+ }
855
+ }
856
+ return found;
857
+ }
858
+ mergeSameKeySelections(selections) {
859
+ if (selections.length === 0) {
860
+ return undefined;
923
861
  }
924
- for (const [key, thatSelections] of that._selections) {
925
- const thisSelections = this._selections.get(key);
926
- if (!thisSelections
927
- || (thisSelections.length < thatSelections.length
928
- || !thatSelections.every(thatSelection => thisSelections.some(thisSelection => thisSelection.contains(thatSelection))))) {
862
+ const first = selections[0];
863
+ if (!first.selectionSet || (first instanceof FragmentSpreadSelection) || selections.length === 1) {
864
+ return first;
865
+ }
866
+ const mergedSubselections = new SelectionSetUpdates();
867
+ for (const selection of selections) {
868
+ mergedSubselections.add(selection.selectionSet);
869
+ }
870
+ return first.withUpdatedSelectionSet(mergedSubselections.toSelectionSet(first.selectionSet.parentType));
871
+ }
872
+ contains(that) {
873
+ for (const [key, thatSelection] of that._keyedSelections) {
874
+ const thisSelection = this._keyedSelections.get(key);
875
+ const otherSelections = this.triviallyNestedSelectionsForKey(this.parentType, key);
876
+ const mergedSelection = this.mergeSameKeySelections([thisSelection].concat(otherSelections).filter(utils_1.isDefined));
877
+ if (!(mergedSelection && mergedSelection.contains(thatSelection))
878
+ && !(thatSelection.isUnecessaryInlineFragment(this.parentType) && this.contains(thatSelection.selectionSet))) {
929
879
  return false;
930
880
  }
931
881
  }
932
882
  return true;
933
883
  }
884
+ diffIfContains(that) {
885
+ if (this.contains(that)) {
886
+ const diff = this.minus(that);
887
+ return { contains: true, diff: diff.isEmpty() ? undefined : diff };
888
+ }
889
+ return { contains: false };
890
+ }
934
891
  minus(that) {
935
- const updated = new SelectionSet(this.parentType, this.fragments);
936
- for (const [key, thisSelections] of this._selections) {
937
- const thatSelections = that._selections.get(key);
938
- if (!thatSelections) {
939
- updated._selections.set(key, thisSelections);
892
+ const updated = new SelectionSetUpdates();
893
+ for (const [key, thisSelection] of this._keyedSelections) {
894
+ const thatSelection = that._keyedSelections.get(key);
895
+ const otherSelections = that.triviallyNestedSelectionsForKey(this.parentType, key);
896
+ const allSelections = thatSelection ? [thatSelection].concat(otherSelections) : otherSelections;
897
+ if (allSelections.length === 0) {
898
+ updated.add(thisSelection);
940
899
  }
941
900
  else {
942
- for (const thisSelection of thisSelections) {
943
- const thatSelection = thatSelections.find((s) => thisSelection.element().equals(s.element()));
944
- if (thatSelection) {
945
- if (thisSelection.selectionSet && thatSelection.selectionSet) {
946
- const updatedSubSelectionSet = thisSelection.selectionSet.minus(thatSelection.selectionSet);
947
- if (!updatedSubSelectionSet.isEmpty()) {
948
- updated._selections.add(key, thisSelection.withUpdatedSubSelection(updatedSubSelectionSet));
949
- }
950
- }
951
- }
952
- else {
953
- updated._selections.add(key, thisSelection);
954
- }
901
+ const selectionDiff = allSelections.reduce((prev, val) => prev === null || prev === void 0 ? void 0 : prev.minus(val), thisSelection);
902
+ if (selectionDiff) {
903
+ updated.add(selectionDiff);
955
904
  }
956
905
  }
957
906
  }
958
- return updated;
907
+ return updated.toSelectionSet(this.parentType, this.fragments);
959
908
  }
960
909
  canRebaseOn(parentTypeToTest) {
961
910
  return this.selections().every((selection) => selection.canAddTo(parentTypeToTest));
962
911
  }
963
- validate() {
912
+ validate(variableDefinitions) {
964
913
  validate(!this.isEmpty(), () => `Invalid empty selection set`);
965
914
  for (const selection of this.selections()) {
966
- selection.validate();
915
+ selection.validate(variableDefinitions);
967
916
  }
968
917
  }
969
918
  isEmpty() {
970
- return this._selections.size === 0;
919
+ return this._selections.length === 0;
971
920
  }
972
921
  toSelectionSetNode() {
973
922
  if (this.isEmpty()) {
@@ -988,13 +937,13 @@ class SelectionSet extends Freezable {
988
937
  };
989
938
  }
990
939
  selectionsInPrintOrder() {
991
- const typenameSelection = this._selections.get(definitions_1.typenameFieldName);
992
- const isNonAliasedTypenameSelection = (s) => s.kind === 'FieldSelection' && !s.field.alias && s.field.name === definitions_1.typenameFieldName;
940
+ const isNonAliasedTypenameSelection = (s) => s.kind === 'FieldSelection' && !s.element.alias && s.element.name === definitions_1.typenameFieldName;
941
+ const typenameSelection = this._selections.find((s) => isNonAliasedTypenameSelection(s));
993
942
  if (typenameSelection) {
994
- return typenameSelection.concat(this.selections().filter(s => !isNonAliasedTypenameSelection(s)));
943
+ return [typenameSelection].concat(this.selections().filter(s => !isNonAliasedTypenameSelection(s)));
995
944
  }
996
945
  else {
997
- return this.selections();
946
+ return this._selections;
998
947
  }
999
948
  }
1000
949
  toOperationPaths() {
@@ -1002,7 +951,7 @@ class SelectionSet extends Freezable {
1002
951
  }
1003
952
  toOperationPathsInternal(parentPaths) {
1004
953
  return this.selections().flatMap((selection) => {
1005
- const updatedPaths = parentPaths.map(path => path.concat(selection.element()));
954
+ const updatedPaths = parentPaths.map(path => path.concat(selection.element));
1006
955
  return selection.selectionSet
1007
956
  ? selection.selectionSet.toOperationPathsInternal(updatedPaths)
1008
957
  : updatedPaths;
@@ -1010,21 +959,20 @@ class SelectionSet extends Freezable {
1010
959
  }
1011
960
  forEachElement(callback) {
1012
961
  var _a;
1013
- const stack = this.selections().concat();
962
+ const stack = this.selectionsInReverseOrder().concat();
1014
963
  while (stack.length > 0) {
1015
964
  const selection = stack.pop();
1016
- callback(selection.element());
1017
- (_a = selection.selectionSet) === null || _a === void 0 ? void 0 : _a.selections(true).forEach((s) => stack.push(s));
965
+ callback(selection.element);
966
+ (_a = selection.selectionSet) === null || _a === void 0 ? void 0 : _a.selectionsInReverseOrder().forEach((s) => stack.push(s));
1018
967
  }
1019
968
  }
1020
- clone() {
1021
- const cloned = new SelectionSet(this.parentType);
969
+ some(predicate) {
1022
970
  for (const selection of this.selections()) {
1023
- const clonedSelection = selection.clone();
1024
- cloned._selections.add(clonedSelection.key(), clonedSelection);
1025
- ++cloned._selectionCount;
971
+ if (predicate(selection.element) || (selection.selectionSet && selection.selectionSet.some(predicate))) {
972
+ return true;
973
+ }
1026
974
  }
1027
- return cloned;
975
+ return false;
1028
976
  }
1029
977
  toOperationString(rootKind, variableDefinitions, operationName, expandFragments = false, prettyPrint = true) {
1030
978
  const indent = prettyPrint ? '' : undefined;
@@ -1040,6 +988,9 @@ class SelectionSet extends Freezable {
1040
988
  return fragmentsDefinitions + rootKind + nameAndVariables + " " + this.toString(expandFragments, true, indent);
1041
989
  }
1042
990
  toString(expandFragments = true, includeExternalBrackets = true, indent) {
991
+ if (this.isEmpty()) {
992
+ return '{}';
993
+ }
1043
994
  if (indent === undefined) {
1044
995
  const selectionsToString = this.selections().map(s => s.toString(expandFragments)).join(' ');
1045
996
  return includeExternalBrackets ? '{ ' + selectionsToString + ' }' : selectionsToString;
@@ -1054,13 +1005,212 @@ class SelectionSet extends Freezable {
1054
1005
  }
1055
1006
  }
1056
1007
  exports.SelectionSet = SelectionSet;
1008
+ class SelectionSetUpdates {
1009
+ constructor() {
1010
+ this.keyedUpdates = new utils_1.MultiMap;
1011
+ }
1012
+ isEmpty() {
1013
+ return this.keyedUpdates.size === 0;
1014
+ }
1015
+ add(selections) {
1016
+ addToKeyedUpdates(this.keyedUpdates, selections);
1017
+ return this;
1018
+ }
1019
+ addAtPath(path, selections) {
1020
+ if (path.length === 0) {
1021
+ if (selections) {
1022
+ addToKeyedUpdates(this.keyedUpdates, selections);
1023
+ }
1024
+ }
1025
+ else {
1026
+ if (path.length === 1 && !selections) {
1027
+ const element = path[0];
1028
+ if (element.kind === 'Field' && element.isLeafField()) {
1029
+ const selection = selectionOfElement(element);
1030
+ this.keyedUpdates.add(selection.key(), selection);
1031
+ return this;
1032
+ }
1033
+ }
1034
+ this.keyedUpdates.add(path[0].key(), { path, selections });
1035
+ }
1036
+ return this;
1037
+ }
1038
+ clone() {
1039
+ const cloned = new SelectionSetUpdates();
1040
+ for (const [key, values] of this.keyedUpdates.entries()) {
1041
+ cloned.keyedUpdates.set(key, Array.from(values));
1042
+ }
1043
+ return cloned;
1044
+ }
1045
+ clear() {
1046
+ this.keyedUpdates.clear();
1047
+ }
1048
+ toSelectionSet(parentType, fragments) {
1049
+ return makeSelectionSet(parentType, this.keyedUpdates, fragments);
1050
+ }
1051
+ }
1052
+ exports.SelectionSetUpdates = SelectionSetUpdates;
1053
+ function addToKeyedUpdates(keyedUpdates, selections) {
1054
+ if (selections instanceof AbstractSelection) {
1055
+ addOneToKeyedUpdates(keyedUpdates, selections);
1056
+ }
1057
+ else {
1058
+ const toAdd = selections instanceof SelectionSet ? selections.selections() : selections;
1059
+ for (const selection of toAdd) {
1060
+ addOneToKeyedUpdates(keyedUpdates, selection);
1061
+ }
1062
+ }
1063
+ }
1064
+ function addOneToKeyedUpdates(keyedUpdates, selection) {
1065
+ if (selection instanceof FragmentSpreadSelection) {
1066
+ keyedUpdates.set(selection.key(), [selection]);
1067
+ }
1068
+ else {
1069
+ keyedUpdates.add(selection.key(), selection);
1070
+ }
1071
+ }
1072
+ function isUnecessaryFragment(parentType, fragment) {
1073
+ return fragment.element.appliedDirectives.length === 0
1074
+ && (!fragment.element.typeCondition || (0, types_1.sameType)(parentType, fragment.element.typeCondition));
1075
+ }
1076
+ function withUnecessaryFragmentsRemoved(parentType, selections) {
1077
+ if (selections instanceof AbstractSelection) {
1078
+ if (selections.kind !== 'FragmentSelection' || !isUnecessaryFragment(parentType, selections)) {
1079
+ return selections;
1080
+ }
1081
+ return withUnecessaryFragmentsRemoved(parentType, selections.selectionSet);
1082
+ }
1083
+ const toCheck = selections instanceof SelectionSet ? selections.selections() : selections;
1084
+ const filtered = [];
1085
+ for (const selection of toCheck) {
1086
+ if (selection.kind === 'FragmentSelection' && isUnecessaryFragment(parentType, selection)) {
1087
+ const subSelections = withUnecessaryFragmentsRemoved(parentType, selection.selectionSet);
1088
+ if (subSelections instanceof AbstractSelection) {
1089
+ filtered.push(subSelections);
1090
+ }
1091
+ else {
1092
+ for (const subSelection of subSelections) {
1093
+ filtered.push(subSelection);
1094
+ }
1095
+ }
1096
+ }
1097
+ else {
1098
+ filtered.push(selection);
1099
+ }
1100
+ }
1101
+ return filtered;
1102
+ }
1103
+ function makeSelection(parentType, updates, fragments) {
1104
+ (0, utils_1.assert)(updates.length > 0, 'Should not be called without any updates');
1105
+ const first = updates[0];
1106
+ if (updates.length === 1 && first instanceof AbstractSelection) {
1107
+ return first.rebaseOn(parentType);
1108
+ }
1109
+ const element = updateElement(first).rebaseOn(parentType);
1110
+ const subSelectionParentType = element.kind === 'Field' ? (0, definitions_1.baseType)(element.definition.type) : element.castedType();
1111
+ if (!(0, definitions_1.isCompositeType)(subSelectionParentType)) {
1112
+ return selectionOfElement(element);
1113
+ }
1114
+ const subSelectionKeyedUpdates = new utils_1.MultiMap();
1115
+ for (const update of updates) {
1116
+ if (update instanceof AbstractSelection) {
1117
+ if (update.selectionSet) {
1118
+ addToKeyedUpdates(subSelectionKeyedUpdates, update.selectionSet);
1119
+ }
1120
+ }
1121
+ else {
1122
+ addSubpathToKeyUpdates(subSelectionKeyedUpdates, subSelectionParentType, update);
1123
+ }
1124
+ }
1125
+ return selectionOfElement(element, makeSelectionSet(subSelectionParentType, subSelectionKeyedUpdates, fragments));
1126
+ }
1127
+ function updateElement(update) {
1128
+ return update instanceof AbstractSelection ? update.element : update.path[0];
1129
+ }
1130
+ function addSubpathToKeyUpdates(keyedUpdates, subSelectionParentType, pathUpdate) {
1131
+ if (pathUpdate.path.length === 1) {
1132
+ if (!pathUpdate.selections) {
1133
+ return;
1134
+ }
1135
+ addToKeyedUpdates(keyedUpdates, withUnecessaryFragmentsRemoved(subSelectionParentType, pathUpdate.selections));
1136
+ }
1137
+ else {
1138
+ keyedUpdates.add(pathUpdate.path[1].key(), { path: pathUpdate.path.slice(1), selections: pathUpdate.selections });
1139
+ }
1140
+ }
1141
+ function makeSelectionSet(parentType, keyedUpdates, fragments) {
1142
+ const selections = new Map();
1143
+ for (const [key, updates] of keyedUpdates.entries()) {
1144
+ selections.set(key, makeSelection(parentType, updates, fragments));
1145
+ }
1146
+ return new SelectionSet(parentType, selections, fragments);
1147
+ }
1148
+ class MutableSelectionSet {
1149
+ constructor(parentType, _updates, memoizer) {
1150
+ this.parentType = parentType;
1151
+ this._updates = _updates;
1152
+ this.memoizer = memoizer;
1153
+ }
1154
+ static empty(parentType) {
1155
+ return this.emptyWithMemoized(parentType, () => ({}));
1156
+ }
1157
+ static emptyWithMemoized(parentType, memoizer) {
1158
+ return new MutableSelectionSet(parentType, new SelectionSetUpdates(), memoizer);
1159
+ }
1160
+ static of(selectionSet) {
1161
+ return this.ofWithMemoized(selectionSet, () => ({}));
1162
+ }
1163
+ static ofWithMemoized(selectionSet, memoizer) {
1164
+ const s = new MutableSelectionSet(selectionSet.parentType, new SelectionSetUpdates(), memoizer);
1165
+ s._updates.add(selectionSet);
1166
+ s.computed = selectionSet;
1167
+ return s;
1168
+ }
1169
+ isEmpty() {
1170
+ return this._updates.isEmpty();
1171
+ }
1172
+ get() {
1173
+ if (!this.computed) {
1174
+ this.computed = this._updates.toSelectionSet(this.parentType);
1175
+ this._updates.clear();
1176
+ this._updates.add(this.computed);
1177
+ }
1178
+ return this.computed;
1179
+ }
1180
+ updates() {
1181
+ this.computed = undefined;
1182
+ this._memoized = undefined;
1183
+ return this._updates;
1184
+ }
1185
+ clone() {
1186
+ const cloned = new MutableSelectionSet(this.parentType, this._updates.clone(), this.memoizer);
1187
+ cloned.computed = this.computed;
1188
+ cloned._memoized = this._memoized;
1189
+ return cloned;
1190
+ }
1191
+ rebaseOn(parentType) {
1192
+ const rebased = new MutableSelectionSet(parentType, new SelectionSetUpdates(), this.memoizer);
1193
+ rebased._updates.add(this.get());
1194
+ return rebased;
1195
+ }
1196
+ memoized() {
1197
+ if (!this._memoized) {
1198
+ this._memoized = this.memoizer(this.get());
1199
+ }
1200
+ return this._memoized;
1201
+ }
1202
+ toString() {
1203
+ return this.get().toString();
1204
+ }
1205
+ }
1206
+ exports.MutableSelectionSet = MutableSelectionSet;
1057
1207
  function allFieldDefinitionsInSelectionSet(selection) {
1058
1208
  const stack = Array.from(selection.selections());
1059
1209
  const allFields = [];
1060
1210
  while (stack.length > 0) {
1061
1211
  const selection = stack.pop();
1062
1212
  if (selection.kind === 'FieldSelection') {
1063
- allFields.push(selection.field.definition);
1213
+ allFields.push(selection.element.definition);
1064
1214
  }
1065
1215
  if (selection.selectionSet) {
1066
1216
  stack.push(...selection.selectionSet.selections());
@@ -1069,59 +1219,137 @@ function allFieldDefinitionsInSelectionSet(selection) {
1069
1219
  return allFields;
1070
1220
  }
1071
1221
  exports.allFieldDefinitionsInSelectionSet = allFieldDefinitionsInSelectionSet;
1072
- function selectionSetOfElement(element, subSelection) {
1073
- const selectionSet = new SelectionSet(element.parentType);
1074
- selectionSet.add(selectionOfElement(element, subSelection));
1075
- return selectionSet;
1222
+ function selectionSetOf(parentType, selection, fragments) {
1223
+ const map = new Map();
1224
+ map.set(selection.key(), selection);
1225
+ return new SelectionSet(parentType, map, fragments);
1226
+ }
1227
+ exports.selectionSetOf = selectionSetOf;
1228
+ function selectionSetOfElement(element, subSelection, fragments) {
1229
+ return selectionSetOf(element.parentType, selectionOfElement(element, subSelection), fragments);
1076
1230
  }
1077
1231
  exports.selectionSetOfElement = selectionSetOfElement;
1078
1232
  function selectionOfElement(element, subSelection) {
1079
1233
  return element.kind === 'Field' ? new FieldSelection(element, subSelection) : new InlineFragmentSelection(element, subSelection);
1080
1234
  }
1081
1235
  exports.selectionOfElement = selectionOfElement;
1082
- class FieldSelection extends Freezable {
1083
- constructor(field, initialSelectionSet) {
1084
- super();
1085
- this.field = field;
1086
- this.kind = 'FieldSelection';
1087
- const type = (0, definitions_1.baseType)(field.definition.type);
1088
- this.selectionSet = (0, definitions_1.isLeafType)(type) ? undefined : (initialSelectionSet ? initialSelectionSet.cloneIfFrozen() : new SelectionSet(type));
1236
+ class AbstractSelection {
1237
+ constructor(element) {
1238
+ this.element = element;
1089
1239
  }
1090
1240
  get parentType() {
1091
- return this.field.parentType;
1241
+ return this.element.parentType;
1092
1242
  }
1093
- us() {
1094
- return this;
1243
+ collectVariables(collector) {
1244
+ var _a;
1245
+ this.element.collectVariables(collector);
1246
+ (_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.collectVariables(collector);
1095
1247
  }
1096
- key() {
1097
- return this.element().responseName();
1248
+ collectUsedFragmentNames(collector) {
1249
+ var _a;
1250
+ (_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.collectUsedFragmentNames(collector);
1098
1251
  }
1099
- element() {
1100
- return this.field;
1252
+ namedFragments() {
1253
+ var _a;
1254
+ return (_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.fragments;
1101
1255
  }
1102
- usedVariables() {
1103
- var _a, _b;
1104
- return (0, definitions_1.mergeVariables)(this.element().variables(), (_b = (_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.usedVariables()) !== null && _b !== void 0 ? _b : []);
1256
+ withUpdatedSelectionSet(selectionSet) {
1257
+ return this.withUpdatedComponents(this.element, selectionSet);
1105
1258
  }
1106
- collectUsedFragmentNames(collector) {
1107
- if (this.selectionSet) {
1108
- this.selectionSet.collectUsedFragmentNames(collector);
1259
+ withUpdatedElement(element) {
1260
+ return this.withUpdatedComponents(element, this.selectionSet);
1261
+ }
1262
+ mapToSelectionSet(mapper) {
1263
+ if (!this.selectionSet) {
1264
+ return this.us();
1265
+ }
1266
+ const updatedSelectionSet = mapper(this.selectionSet);
1267
+ return updatedSelectionSet === this.selectionSet
1268
+ ? this.us()
1269
+ : this.withUpdatedSelectionSet(updatedSelectionSet);
1270
+ }
1271
+ minus(that) {
1272
+ if (this.selectionSet && that.selectionSet) {
1273
+ const updatedSubSelectionSet = this.selectionSet.minus(that.selectionSet);
1274
+ if (!updatedSubSelectionSet.isEmpty()) {
1275
+ return this.withUpdatedSelectionSet(updatedSubSelectionSet);
1276
+ }
1277
+ }
1278
+ return undefined;
1279
+ }
1280
+ tryOptimizeSubselectionOnce(_) {
1281
+ (0, utils_1.assert)(false, `UNSUPPORTED`);
1282
+ }
1283
+ tryOptimizeSubselectionWithFragments({ parentType, subSelection, fragments, fragmentFilter, }) {
1284
+ let candidates = fragments.maybeApplyingAtType(parentType);
1285
+ if (fragmentFilter) {
1286
+ candidates = candidates.filter(fragmentFilter);
1109
1287
  }
1288
+ let shouldTryAgain;
1289
+ do {
1290
+ const { spread, optimizedSelection, hasDiff } = this.tryOptimizeSubselectionOnce({ parentType, subSelection, candidates, fragments });
1291
+ if (optimizedSelection) {
1292
+ subSelection = optimizedSelection;
1293
+ }
1294
+ else if (spread) {
1295
+ return spread;
1296
+ }
1297
+ shouldTryAgain = !!spread && !!hasDiff;
1298
+ if (shouldTryAgain) {
1299
+ candidates = candidates.filter((c) => c !== (spread === null || spread === void 0 ? void 0 : spread.namedFragment));
1300
+ }
1301
+ } while (shouldTryAgain);
1302
+ return subSelection;
1303
+ }
1304
+ }
1305
+ class FieldSelection extends AbstractSelection {
1306
+ constructor(field, _selectionSet) {
1307
+ super(field);
1308
+ this._selectionSet = _selectionSet;
1309
+ this.kind = 'FieldSelection';
1310
+ }
1311
+ get selectionSet() {
1312
+ return this._selectionSet;
1313
+ }
1314
+ us() {
1315
+ return this;
1316
+ }
1317
+ withUpdatedComponents(field, selectionSet) {
1318
+ return new FieldSelection(field, selectionSet);
1319
+ }
1320
+ key() {
1321
+ return this.element.key();
1110
1322
  }
1111
1323
  optimize(fragments) {
1112
- const optimizedSelection = this.selectionSet ? this.selectionSet.optimize(fragments) : undefined;
1113
- const fieldBaseType = (0, definitions_1.baseType)(this.field.definition.type);
1324
+ let optimizedSelection = this.selectionSet ? this.selectionSet.optimize(fragments) : undefined;
1325
+ const fieldBaseType = (0, definitions_1.baseType)(this.element.definition.type);
1114
1326
  if ((0, definitions_1.isCompositeType)(fieldBaseType) && optimizedSelection) {
1115
- for (const candidate of fragments.maybeApplyingAtType(fieldBaseType)) {
1116
- if (optimizedSelection.equals(candidate.selectionSet)) {
1117
- const fragmentSelection = new FragmentSpreadSelection(fieldBaseType, fragments, candidate.name);
1118
- return new FieldSelection(this.field, selectionSetOf(fieldBaseType, fragmentSelection));
1119
- }
1120
- }
1327
+ const optimized = this.tryOptimizeSubselectionWithFragments({
1328
+ parentType: fieldBaseType,
1329
+ subSelection: optimizedSelection,
1330
+ fragments,
1331
+ fragmentFilter: (f) => f.appliedDirectives.length === 0,
1332
+ });
1333
+ (0, utils_1.assert)(!(optimized instanceof FragmentSpreadSelection), 'tryOptimizeSubselectionOnce should never return only a spread');
1334
+ optimizedSelection = optimized;
1121
1335
  }
1122
1336
  return this.selectionSet === optimizedSelection
1123
1337
  ? this
1124
- : new FieldSelection(this.field, optimizedSelection);
1338
+ : new FieldSelection(this.element, optimizedSelection);
1339
+ }
1340
+ tryOptimizeSubselectionOnce({ parentType, subSelection, candidates, fragments, }) {
1341
+ let optimizedSelection = subSelection;
1342
+ for (const candidate of candidates) {
1343
+ const { contains, diff } = optimizedSelection.diffIfContains(candidate.selectionSet);
1344
+ if (contains) {
1345
+ const spread = new FragmentSpreadSelection(parentType, fragments, candidate, []);
1346
+ optimizedSelection = diff
1347
+ ? new SelectionSetUpdates().add(spread).add(diff).toSelectionSet(parentType, fragments)
1348
+ : selectionSetOf(parentType, spread);
1349
+ return { spread, optimizedSelection, hasDiff: !!diff };
1350
+ }
1351
+ }
1352
+ return {};
1125
1353
  }
1126
1354
  filter(predicate) {
1127
1355
  if (!this.selectionSet) {
@@ -1130,99 +1358,96 @@ class FieldSelection extends Freezable {
1130
1358
  const updatedSelectionSet = this.selectionSet.filter(predicate);
1131
1359
  const thisWithFilteredSelectionSet = this.selectionSet === updatedSelectionSet
1132
1360
  ? this
1133
- : new FieldSelection(this.field, updatedSelectionSet);
1361
+ : new FieldSelection(this.element, updatedSelectionSet);
1134
1362
  return predicate(thisWithFilteredSelectionSet) ? thisWithFilteredSelectionSet : undefined;
1135
1363
  }
1136
- freezeInternals() {
1364
+ validate(variableDefinitions) {
1137
1365
  var _a;
1138
- (_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.freeze();
1139
- }
1140
- expandFragments(names, updateSelectionSetFragments = true) {
1141
- const expandedSelection = this.selectionSet ? this.selectionSet.expandFragments(names, updateSelectionSetFragments) : undefined;
1142
- return this.selectionSet === expandedSelection
1143
- ? this
1144
- : new FieldSelection(this.field, expandedSelection);
1366
+ this.element.validate(variableDefinitions);
1367
+ validate(this.element.isLeafField() || (this.selectionSet && !this.selectionSet.isEmpty()), () => `Invalid empty selection set for field "${this.element.definition.coordinate}" of non-leaf type ${this.element.definition.type}`, this.element.definition.sourceAST);
1368
+ (_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.validate(variableDefinitions);
1145
1369
  }
1146
- fieldArgumentsToAST() {
1147
- const entries = Object.entries(this.field.args);
1148
- if (entries.length === 0) {
1149
- return undefined;
1370
+ rebaseOn(parentType) {
1371
+ if (this.element.parentType === parentType) {
1372
+ return this;
1150
1373
  }
1151
- return entries.map(([n, v]) => {
1152
- return {
1153
- kind: graphql_1.Kind.ARGUMENT,
1154
- name: { kind: graphql_1.Kind.NAME, value: n },
1155
- value: (0, values_1.valueToAST)(v, this.field.definition.argument(n).type),
1156
- };
1157
- });
1158
- }
1159
- validate() {
1160
- var _a;
1161
- this.field.validate();
1162
- validate(!(this.selectionSet && this.selectionSet.isEmpty()), () => `Invalid empty selection set for field "${this.field.definition.coordinate}" of non-leaf type ${this.field.definition.type}`, this.field.definition.sourceAST);
1163
- (_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.validate();
1164
- }
1165
- updateForAddingTo(selectionSet) {
1166
- var _a;
1167
- const updatedField = this.field.updateForAddingTo(selectionSet);
1168
- if (this.field === updatedField) {
1169
- return this.cloneIfFrozen();
1170
- }
1171
- const updatedBaseType = (0, definitions_1.baseType)(updatedField.definition.type);
1172
- let updatedSelectionSet;
1173
- if (this.selectionSet && this.selectionSet.parentType !== updatedBaseType) {
1174
- (0, utils_1.assert)((0, definitions_1.isCompositeType)(updatedBaseType), `Expected ${updatedBaseType.coordinate} to be composite but ${updatedBaseType.kind}`);
1175
- updatedSelectionSet = new SelectionSet(updatedBaseType);
1176
- for (const selection of this.selectionSet.selections()) {
1177
- updatedSelectionSet.add(selection);
1178
- }
1374
+ const rebasedElement = this.element.rebaseOn(parentType);
1375
+ if (!this.selectionSet) {
1376
+ return this.withUpdatedElement(rebasedElement);
1179
1377
  }
1180
- else {
1181
- updatedSelectionSet = (_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.cloneIfFrozen();
1378
+ const rebasedBase = (0, definitions_1.baseType)(rebasedElement.definition.type);
1379
+ if (rebasedBase === this.selectionSet.parentType) {
1380
+ return this.withUpdatedElement(rebasedElement);
1182
1381
  }
1183
- return new FieldSelection(updatedField, updatedSelectionSet);
1382
+ validate((0, definitions_1.isCompositeType)(rebasedBase), () => `Cannot rebase field selection ${this} on ${parentType}: rebased field base return type ${rebasedBase} is not composite`);
1383
+ return this.withUpdatedComponents(rebasedElement, this.selectionSet.rebaseOn(rebasedBase));
1184
1384
  }
1185
1385
  canAddTo(parentType) {
1186
- if (this.field.parentType === parentType) {
1386
+ if (this.element.parentType === parentType) {
1187
1387
  return true;
1188
1388
  }
1189
- const type = this.field.typeIfAddedTo(parentType);
1389
+ const type = this.element.typeIfAddedTo(parentType);
1190
1390
  if (!type) {
1191
1391
  return false;
1192
1392
  }
1193
1393
  const base = (0, definitions_1.baseType)(type);
1194
1394
  if (this.selectionSet && this.selectionSet.parentType !== base) {
1195
- (0, utils_1.assert)((0, definitions_1.isCompositeType)(base), () => `${this.field} should have a selection set as it's type is not a composite`);
1395
+ (0, utils_1.assert)((0, definitions_1.isCompositeType)(base), () => `${this.element} should have a selection set as it's type is not a composite`);
1196
1396
  return this.selectionSet.selections().every((s) => s.canAddTo(base));
1197
1397
  }
1198
1398
  return true;
1199
1399
  }
1200
1400
  toSelectionNode() {
1201
1401
  var _a;
1202
- const alias = this.field.alias ? { kind: graphql_1.Kind.NAME, value: this.field.alias, } : undefined;
1402
+ const alias = this.element.alias ? { kind: graphql_1.Kind.NAME, value: this.element.alias, } : undefined;
1203
1403
  return {
1204
1404
  kind: graphql_1.Kind.FIELD,
1205
1405
  name: {
1206
1406
  kind: graphql_1.Kind.NAME,
1207
- value: this.field.name,
1407
+ value: this.element.name,
1208
1408
  },
1209
1409
  alias,
1210
- arguments: this.fieldArgumentsToAST(),
1211
- directives: this.element().appliedDirectivesToDirectiveNodes(),
1410
+ arguments: this.element.argumentsToNodes(),
1411
+ directives: this.element.appliedDirectivesToDirectiveNodes(),
1212
1412
  selectionSet: (_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.toSelectionSetNode()
1213
1413
  };
1214
1414
  }
1215
- withUpdatedSubSelection(newSubSelection) {
1216
- return new FieldSelection(this.field, newSubSelection);
1415
+ withoutDefer(labelsToRemove) {
1416
+ return this.mapToSelectionSet((s) => s.withoutDefer(labelsToRemove));
1417
+ }
1418
+ withNormalizedDefer(normalizer) {
1419
+ return this.mapToSelectionSet((s) => s.withNormalizedDefer(normalizer));
1420
+ }
1421
+ hasDefer() {
1422
+ var _a;
1423
+ return !!((_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.hasDefer());
1424
+ }
1425
+ expandAllFragments() {
1426
+ return this.mapToSelectionSet((s) => s.expandAllFragments());
1427
+ }
1428
+ trimUnsatisfiableBranches(_) {
1429
+ var _a;
1430
+ if (!this.selectionSet) {
1431
+ return this;
1432
+ }
1433
+ const base = (0, definitions_1.baseType)(this.element.definition.type);
1434
+ (0, utils_1.assert)((0, definitions_1.isCompositeType)(base), () => `Field ${this.element} should not have a sub-selection`);
1435
+ const trimmed = this.mapToSelectionSet((s) => s.trimUnsatisfiableBranches(base));
1436
+ if ((_a = trimmed.selectionSet) === null || _a === void 0 ? void 0 : _a.isEmpty()) {
1437
+ return trimmed.withUpdatedSelectionSet(selectionSetOfElement(new Field(base.typenameField(), undefined, [new definitions_1.Directive('include', { 'if': false })])));
1438
+ }
1439
+ else {
1440
+ return trimmed;
1441
+ }
1217
1442
  }
1218
- withUpdatedField(newField) {
1219
- return new FieldSelection(newField, this.selectionSet);
1443
+ expandFragments(names, updatedFragments) {
1444
+ return this.mapToSelectionSet((s) => s.expandFragments(names, updatedFragments));
1220
1445
  }
1221
1446
  equals(that) {
1222
1447
  if (this === that) {
1223
1448
  return true;
1224
1449
  }
1225
- if (!(that instanceof FieldSelection) || !this.field.equals(that.field)) {
1450
+ if (!(that instanceof FieldSelection) || !this.element.equals(that.element)) {
1226
1451
  return false;
1227
1452
  }
1228
1453
  if (!this.selectionSet) {
@@ -1231,7 +1456,7 @@ class FieldSelection extends Freezable {
1231
1456
  return !!that.selectionSet && this.selectionSet.equals(that.selectionSet);
1232
1457
  }
1233
1458
  contains(that) {
1234
- if (!(that instanceof FieldSelection) || !this.field.equals(that.field)) {
1459
+ if (!(that instanceof FieldSelection) || !this.element.equals(that.element)) {
1235
1460
  return false;
1236
1461
  }
1237
1462
  if (!that.selectionSet) {
@@ -1239,126 +1464,83 @@ class FieldSelection extends Freezable {
1239
1464
  }
1240
1465
  return !!this.selectionSet && this.selectionSet.contains(that.selectionSet);
1241
1466
  }
1242
- namedFragments() {
1243
- var _a;
1244
- return (_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.fragments;
1245
- }
1246
- withoutDefer(labelsToRemove) {
1247
- var _a;
1248
- const updatedSubSelections = (_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.withoutDefer(labelsToRemove);
1249
- return updatedSubSelections === this.selectionSet
1250
- ? this
1251
- : new FieldSelection(this.field, updatedSubSelections);
1252
- }
1253
- withNormalizedDefer(normalizer) {
1254
- var _a;
1255
- const updatedSubSelections = (_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.withNormalizedDefer(normalizer);
1256
- return updatedSubSelections === this.selectionSet
1257
- ? this
1258
- : new FieldSelection(this.field, updatedSubSelections);
1259
- }
1260
- clone() {
1261
- if (!this.selectionSet) {
1262
- return this;
1263
- }
1264
- return new FieldSelection(this.field, this.selectionSet.clone());
1467
+ isUnecessaryInlineFragment(_) {
1468
+ return false;
1265
1469
  }
1266
1470
  toString(expandFragments = true, indent) {
1267
- return (indent !== null && indent !== void 0 ? indent : '') + this.field + (this.selectionSet ? ' ' + this.selectionSet.toString(expandFragments, true, indent) : '');
1471
+ return (indent !== null && indent !== void 0 ? indent : '') + this.element + (this.selectionSet ? ' ' + this.selectionSet.toString(expandFragments, true, indent) : '');
1268
1472
  }
1269
1473
  }
1270
1474
  exports.FieldSelection = FieldSelection;
1271
- class FragmentSelection extends Freezable {
1475
+ class FragmentSelection extends AbstractSelection {
1272
1476
  constructor() {
1273
1477
  super(...arguments);
1274
1478
  this.kind = 'FragmentSelection';
1275
1479
  }
1276
- get parentType() {
1277
- return this.element().parentType;
1278
- }
1279
1480
  us() {
1280
1481
  return this;
1281
1482
  }
1282
1483
  validateDeferAndStream() {
1283
- if (this.element().hasDefer() || this.element().hasStream()) {
1284
- const schemaDef = this.element().schema().schemaDefinition;
1285
- const parentType = this.element().parentType;
1484
+ if (this.element.hasDefer() || this.element.hasStream()) {
1485
+ const schemaDef = this.element.schema().schemaDefinition;
1486
+ const parentType = this.parentType;
1286
1487
  validate(schemaDef.rootType('mutation') !== parentType && schemaDef.rootType('subscription') !== parentType, () => { var _a; return `The @defer and @stream directives cannot be used on ${(_a = schemaDef.roots().filter((t) => t.type === parentType).pop()) === null || _a === void 0 ? void 0 : _a.rootKind} root type "${parentType}"`; });
1287
1488
  }
1288
1489
  }
1289
- usedVariables() {
1290
- return (0, definitions_1.mergeVariables)(this.element().variables(), this.selectionSet.usedVariables());
1291
- }
1292
1490
  filter(predicate) {
1293
1491
  const selectionSet = this.selectionSet;
1294
1492
  const updatedSelectionSet = selectionSet.filter(predicate);
1295
1493
  const thisWithFilteredSelectionSet = updatedSelectionSet === selectionSet
1296
1494
  ? this
1297
- : new InlineFragmentSelection(this.element(), updatedSelectionSet);
1495
+ : new InlineFragmentSelection(this.element, updatedSelectionSet);
1298
1496
  return predicate(thisWithFilteredSelectionSet) ? thisWithFilteredSelectionSet : undefined;
1299
1497
  }
1300
- freezeInternals() {
1301
- this.selectionSet.freeze();
1302
- }
1303
- equals(that) {
1304
- if (this === that) {
1305
- return true;
1306
- }
1307
- return (that instanceof FragmentSelection)
1308
- && this.element().equals(that.element())
1309
- && this.selectionSet.equals(that.selectionSet);
1310
- }
1311
- contains(that) {
1312
- return (that instanceof FragmentSelection)
1313
- && this.element().equals(that.element())
1314
- && this.selectionSet.contains(that.selectionSet);
1498
+ hasDefer() {
1499
+ return this.element.hasDefer() || this.selectionSet.hasDefer();
1315
1500
  }
1316
- clone() {
1317
- return new InlineFragmentSelection(this.element(), this.selectionSet.clone());
1501
+ isUnecessaryInlineFragment(parentType) {
1502
+ return this.element.appliedDirectives.length === 0
1503
+ && !!this.element.typeCondition
1504
+ && (this.element.typeCondition.name === parentType.name
1505
+ || ((0, definitions_1.isObjectType)(parentType) && (0, definitions_1.possibleRuntimeTypes)(this.element.typeCondition).some((t) => t.name === parentType.name)));
1318
1506
  }
1319
1507
  }
1320
1508
  exports.FragmentSelection = FragmentSelection;
1321
1509
  class InlineFragmentSelection extends FragmentSelection {
1322
- constructor(fragmentElement, initialSelectionSet) {
1323
- super();
1324
- this.fragmentElement = fragmentElement;
1325
- this._selectionSet = initialSelectionSet
1326
- ? initialSelectionSet.cloneIfFrozen()
1327
- : new SelectionSet(fragmentElement.typeCondition ? fragmentElement.typeCondition : fragmentElement.parentType);
1510
+ constructor(fragment, _selectionSet) {
1511
+ super(fragment);
1512
+ this._selectionSet = _selectionSet;
1513
+ }
1514
+ get selectionSet() {
1515
+ return this._selectionSet;
1328
1516
  }
1329
1517
  key() {
1330
- var _a, _b;
1331
- return (_b = (_a = this.element().typeCondition) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '';
1518
+ return this.element.key();
1332
1519
  }
1333
- validate() {
1520
+ withUpdatedComponents(fragment, selectionSet) {
1521
+ return new InlineFragmentSelection(fragment, selectionSet);
1522
+ }
1523
+ validate(variableDefinitions) {
1334
1524
  this.validateDeferAndStream();
1335
- validate(!this.selectionSet.isEmpty(), () => `Invalid empty selection set for fragment "${this.element()}"`);
1336
- this.selectionSet.validate();
1525
+ validate(!this.selectionSet.isEmpty(), () => `Invalid empty selection set for fragment "${this.element}"`);
1526
+ this.selectionSet.validate(variableDefinitions);
1337
1527
  }
1338
- updateForAddingTo(selectionSet) {
1339
- var _a;
1340
- const updatedFragment = this.element().updateForAddingTo(selectionSet);
1341
- if (this.element() === updatedFragment) {
1342
- return this.cloneIfFrozen();
1343
- }
1344
- const updatedCastedType = updatedFragment.castedType();
1345
- let updatedSelectionSet;
1346
- if (this.selectionSet.parentType !== updatedCastedType) {
1347
- updatedSelectionSet = new SelectionSet(updatedCastedType);
1348
- for (const selection of this.selectionSet.selections()) {
1349
- updatedSelectionSet.add(selection);
1350
- }
1528
+ rebaseOn(parentType) {
1529
+ if (this.parentType === parentType) {
1530
+ return this;
1351
1531
  }
1352
- else {
1353
- updatedSelectionSet = (_a = this.selectionSet) === null || _a === void 0 ? void 0 : _a.cloneIfFrozen();
1532
+ const rebasedFragment = this.element.rebaseOn(parentType);
1533
+ const rebasedCastedType = rebasedFragment.castedType();
1534
+ if (rebasedCastedType === this.selectionSet.parentType) {
1535
+ return this.withUpdatedElement(rebasedFragment);
1354
1536
  }
1355
- return new InlineFragmentSelection(updatedFragment, updatedSelectionSet);
1537
+ return this.withUpdatedComponents(rebasedFragment, this.selectionSet.rebaseOn(rebasedCastedType));
1356
1538
  }
1357
1539
  canAddTo(parentType) {
1358
- if (this.element().parentType === parentType) {
1540
+ if (this.element.parentType === parentType) {
1359
1541
  return true;
1360
1542
  }
1361
- const type = this.element().castedTypeIfAddedTo(parentType);
1543
+ const type = this.element.castedTypeIfAddedTo(parentType);
1362
1544
  if (!type) {
1363
1545
  return false;
1364
1546
  }
@@ -1367,17 +1549,8 @@ class InlineFragmentSelection extends FragmentSelection {
1367
1549
  }
1368
1550
  return true;
1369
1551
  }
1370
- get selectionSet() {
1371
- return this._selectionSet;
1372
- }
1373
- namedFragments() {
1374
- return this.selectionSet.fragments;
1375
- }
1376
- element() {
1377
- return this.fragmentElement;
1378
- }
1379
1552
  toSelectionNode() {
1380
- const typeCondition = this.element().typeCondition;
1553
+ const typeCondition = this.element.typeCondition;
1381
1554
  return {
1382
1555
  kind: graphql_1.Kind.INLINE_FRAGMENT,
1383
1556
  typeCondition: typeCondition
@@ -1389,103 +1562,195 @@ class InlineFragmentSelection extends FragmentSelection {
1389
1562
  },
1390
1563
  }
1391
1564
  : undefined,
1392
- directives: this.element().appliedDirectivesToDirectiveNodes(),
1565
+ directives: this.element.appliedDirectivesToDirectiveNodes(),
1393
1566
  selectionSet: this.selectionSet.toSelectionSetNode()
1394
1567
  };
1395
1568
  }
1396
1569
  optimize(fragments) {
1397
1570
  let optimizedSelection = this.selectionSet.optimize(fragments);
1398
- const typeCondition = this.element().typeCondition;
1571
+ const typeCondition = this.element.typeCondition;
1399
1572
  if (typeCondition) {
1400
- for (const candidate of fragments.maybeApplyingAtType(typeCondition)) {
1401
- if (optimizedSelection.equals(candidate.selectionSet)) {
1402
- const spread = new FragmentSpreadSelection(this.element().parentType, fragments, candidate.name);
1403
- if ((0, types_1.sameType)(typeCondition, candidate.typeCondition)) {
1404
- this.fragmentElement.appliedDirectives.forEach((directive) => {
1405
- spread.element().applyDirective(directive.definition, directive.arguments());
1406
- });
1407
- return spread;
1408
- }
1409
- optimizedSelection = selectionSetOf(spread.element().parentType, spread);
1410
- break;
1411
- }
1573
+ const optimized = this.tryOptimizeSubselectionWithFragments({
1574
+ parentType: typeCondition,
1575
+ subSelection: optimizedSelection,
1576
+ fragments,
1577
+ });
1578
+ if (optimized instanceof FragmentSpreadSelection) {
1579
+ return optimized;
1412
1580
  }
1581
+ optimizedSelection = optimized;
1413
1582
  }
1414
1583
  return this.selectionSet === optimizedSelection
1415
1584
  ? this
1416
- : new InlineFragmentSelection(this.fragmentElement, optimizedSelection);
1417
- }
1418
- expandFragments(names, updateSelectionSetFragments = true) {
1419
- const expandedSelection = this.selectionSet.expandFragments(names, updateSelectionSetFragments);
1420
- return this.selectionSet === expandedSelection
1421
- ? this
1422
- : new InlineFragmentSelection(this.element(), expandedSelection);
1423
- }
1424
- collectUsedFragmentNames(collector) {
1425
- this.selectionSet.collectUsedFragmentNames(collector);
1585
+ : new InlineFragmentSelection(this.element, optimizedSelection);
1586
+ }
1587
+ tryOptimizeSubselectionOnce({ parentType, subSelection, candidates, fragments, }) {
1588
+ let optimizedSelection = subSelection;
1589
+ for (const candidate of candidates) {
1590
+ const { contains, diff } = optimizedSelection.diffIfContains(candidate.selectionSet);
1591
+ if (contains) {
1592
+ if (!diff && (0, types_1.sameType)(this.element.typeCondition, candidate.typeCondition)) {
1593
+ let spreadDirectives = this.element.appliedDirectives;
1594
+ if (candidate.appliedDirectives.length > 0) {
1595
+ const { isSubset, difference } = diffDirectives(this.element.appliedDirectives, candidate.appliedDirectives);
1596
+ if (!isSubset) {
1597
+ continue;
1598
+ }
1599
+ spreadDirectives = difference;
1600
+ }
1601
+ return {
1602
+ spread: new FragmentSpreadSelection(this.parentType, fragments, candidate, spreadDirectives),
1603
+ };
1604
+ }
1605
+ if (candidate.appliedDirectives.length > 0) {
1606
+ continue;
1607
+ }
1608
+ const spread = new FragmentSpreadSelection(parentType, fragments, candidate, []);
1609
+ optimizedSelection = diff
1610
+ ? new SelectionSetUpdates().add(spread).add(diff).toSelectionSet(parentType, fragments)
1611
+ : selectionSetOf(parentType, spread);
1612
+ return { spread, optimizedSelection, hasDiff: !!diff };
1613
+ }
1614
+ }
1615
+ return {};
1426
1616
  }
1427
1617
  withoutDefer(labelsToRemove) {
1428
- const updatedSubSelections = this.selectionSet.withoutDefer(labelsToRemove);
1429
- const deferArgs = this.fragmentElement.deferDirectiveArgs();
1618
+ const newSelection = this.selectionSet.withoutDefer(labelsToRemove);
1619
+ const deferArgs = this.element.deferDirectiveArgs();
1430
1620
  const hasDeferToRemove = deferArgs && (!labelsToRemove || (deferArgs.label && labelsToRemove.has(deferArgs.label)));
1431
- if (updatedSubSelections === this.selectionSet && !hasDeferToRemove) {
1621
+ if (newSelection === this.selectionSet && !hasDeferToRemove) {
1432
1622
  return this;
1433
1623
  }
1434
- const newFragment = hasDeferToRemove ? this.fragmentElement.withoutDefer() : this.fragmentElement;
1435
- if (!newFragment) {
1436
- return updatedSubSelections;
1624
+ const newElement = hasDeferToRemove ? this.element.withoutDefer() : this.element;
1625
+ if (!newElement) {
1626
+ return newSelection;
1437
1627
  }
1438
- return new InlineFragmentSelection(newFragment, updatedSubSelections);
1628
+ return this.withUpdatedComponents(newElement, newSelection);
1439
1629
  }
1440
1630
  withNormalizedDefer(normalizer) {
1441
- const newFragment = this.fragmentElement.withNormalizedDefer(normalizer);
1442
- const updatedSubSelections = this.selectionSet.withNormalizedDefer(normalizer);
1443
- if (!newFragment) {
1444
- return updatedSubSelections;
1631
+ const newElement = this.element.withNormalizedDefer(normalizer);
1632
+ const newSelection = this.selectionSet.withNormalizedDefer(normalizer);
1633
+ if (!newElement) {
1634
+ return newSelection;
1445
1635
  }
1446
- return newFragment === this.fragmentElement && updatedSubSelections === this.selectionSet
1636
+ return newElement === this.element && newSelection === this.selectionSet
1447
1637
  ? this
1448
- : new InlineFragmentSelection(newFragment, updatedSubSelections);
1638
+ : this.withUpdatedComponents(newElement, newSelection);
1639
+ }
1640
+ trimUnsatisfiableBranches(currentType) {
1641
+ var _a, _b;
1642
+ const thisCondition = this.element.typeCondition;
1643
+ if (this.element.appliedDirectives.length === 0) {
1644
+ if (!thisCondition || currentType === this.element.typeCondition) {
1645
+ const trimmed = this.selectionSet.trimUnsatisfiableBranches(currentType);
1646
+ return trimmed.isEmpty() ? undefined : trimmed;
1647
+ }
1648
+ if ((0, definitions_1.isObjectType)(currentType)) {
1649
+ if ((0, definitions_1.isObjectType)(thisCondition) || !(0, definitions_1.possibleRuntimeTypes)(thisCondition).includes(currentType)) {
1650
+ return undefined;
1651
+ }
1652
+ else {
1653
+ const trimmed = this.selectionSet.trimUnsatisfiableBranches(currentType);
1654
+ return trimmed.isEmpty() ? undefined : trimmed;
1655
+ }
1656
+ }
1657
+ }
1658
+ const trimmedSelectionSet = this.selectionSet.trimUnsatisfiableBranches((_a = this.element.typeCondition) !== null && _a !== void 0 ? _a : this.parentType);
1659
+ if (trimmedSelectionSet.isEmpty()) {
1660
+ if (this.element.appliedDirectives.length === 0) {
1661
+ return undefined;
1662
+ }
1663
+ else {
1664
+ return this.withUpdatedSelectionSet(selectionSetOfElement(new Field(((_b = this.element.typeCondition) !== null && _b !== void 0 ? _b : this.parentType).typenameField(), undefined, [new definitions_1.Directive('include', { 'if': false })])));
1665
+ }
1666
+ }
1667
+ if (this.element.appliedDirectives.length === 0 && (0, definitions_1.isAbstractType)(thisCondition)) {
1668
+ (0, utils_1.assert)(!(0, definitions_1.isObjectType)(currentType), () => `Should not have got here if ${currentType} is an object type`);
1669
+ const currentRuntimes = (0, definitions_1.possibleRuntimeTypes)(currentType);
1670
+ const liftableSelections = [];
1671
+ for (const selection of trimmedSelectionSet.selections()) {
1672
+ if (selection.kind === 'FragmentSelection'
1673
+ && selection.element.typeCondition
1674
+ && (0, definitions_1.isObjectType)(selection.element.typeCondition)
1675
+ && currentRuntimes.includes(selection.element.typeCondition)) {
1676
+ liftableSelections.push(selection);
1677
+ }
1678
+ }
1679
+ if (liftableSelections.length === trimmedSelectionSet.selections().length) {
1680
+ return trimmedSelectionSet;
1681
+ }
1682
+ if (liftableSelections.length > 0) {
1683
+ const newSet = new SelectionSetUpdates();
1684
+ newSet.add(liftableSelections);
1685
+ newSet.add(this.withUpdatedSelectionSet(trimmedSelectionSet.filter((s) => !liftableSelections.includes(s))));
1686
+ return newSet.toSelectionSet(this.parentType);
1687
+ }
1688
+ }
1689
+ return this.selectionSet === trimmedSelectionSet ? this : this.withUpdatedSelectionSet(trimmedSelectionSet);
1690
+ }
1691
+ expandAllFragments() {
1692
+ return this.mapToSelectionSet((s) => s.expandAllFragments());
1693
+ }
1694
+ expandFragments(names, updatedFragments) {
1695
+ return this.mapToSelectionSet((s) => s.expandFragments(names, updatedFragments));
1696
+ }
1697
+ equals(that) {
1698
+ if (this === that) {
1699
+ return true;
1700
+ }
1701
+ return (that instanceof FragmentSelection)
1702
+ && this.element.equals(that.element)
1703
+ && this.selectionSet.equals(that.selectionSet);
1449
1704
  }
1450
- withUpdatedSubSelection(newSubSelection) {
1451
- return new InlineFragmentSelection(this.fragmentElement, newSubSelection);
1705
+ contains(that) {
1706
+ return (that instanceof FragmentSelection)
1707
+ && this.element.equals(that.element)
1708
+ && this.selectionSet.contains(that.selectionSet);
1452
1709
  }
1453
1710
  toString(expandFragments = true, indent) {
1454
- return (indent !== null && indent !== void 0 ? indent : '') + this.fragmentElement + ' ' + this.selectionSet.toString(expandFragments, true, indent);
1711
+ return (indent !== null && indent !== void 0 ? indent : '') + this.element + ' ' + this.selectionSet.toString(expandFragments, true, indent);
1712
+ }
1713
+ }
1714
+ function diffDirectives(superset, maybeSubset) {
1715
+ if (maybeSubset.every((d) => superset.some((s) => (0, definitions_1.sameDirectiveApplication)(d, s)))) {
1716
+ return { isSubset: true, difference: superset.filter((s) => !maybeSubset.some((d) => (0, definitions_1.sameDirectiveApplication)(d, s))) };
1717
+ }
1718
+ else {
1719
+ return { isSubset: false, difference: [] };
1455
1720
  }
1456
1721
  }
1457
1722
  class FragmentSpreadSelection extends FragmentSelection {
1458
- constructor(sourceType, fragments, fragmentName) {
1459
- super();
1723
+ constructor(sourceType, fragments, namedFragment, spreadDirectives) {
1724
+ super(new FragmentElement(sourceType, namedFragment.typeCondition, namedFragment.appliedDirectives.concat(spreadDirectives)));
1460
1725
  this.fragments = fragments;
1461
- const fragmentDefinition = fragments.get(fragmentName);
1462
- validate(fragmentDefinition, () => `Unknown fragment "...${fragmentName}"`);
1463
- this.namedFragment = fragmentDefinition;
1464
- this._element = new FragmentElement(sourceType, fragmentDefinition.typeCondition);
1465
- for (const directive of fragmentDefinition.appliedDirectives) {
1466
- this._element.applyDirective(directive.definition, directive.arguments());
1467
- }
1726
+ this.namedFragment = namedFragment;
1727
+ this.spreadDirectives = spreadDirectives;
1728
+ }
1729
+ get selectionSet() {
1730
+ return this.namedFragment.selectionSet;
1468
1731
  }
1469
1732
  key() {
1470
- return '...' + this.namedFragment.name;
1733
+ if (!this.computedKey) {
1734
+ this.computedKey = '...' + this.namedFragment.name + (this.spreadDirectives.length === 0 ? '' : ' ' + this.spreadDirectives.join(' '));
1735
+ }
1736
+ return this.computedKey;
1471
1737
  }
1472
- element() {
1473
- return this._element;
1738
+ withUpdatedComponents(_fragment, _selectionSet) {
1739
+ (0, utils_1.assert)(false, `Unsupported`);
1740
+ }
1741
+ trimUnsatisfiableBranches(_) {
1742
+ return this;
1474
1743
  }
1475
1744
  namedFragments() {
1476
1745
  return this.fragments;
1477
1746
  }
1478
- get selectionSet() {
1479
- return this.namedFragment.selectionSet;
1480
- }
1481
1747
  validate() {
1482
1748
  this.validateDeferAndStream();
1483
1749
  }
1484
1750
  toSelectionNode() {
1485
- const spreadDirectives = this.spreadDirectives();
1486
- const directiveNodes = spreadDirectives.length === 0
1751
+ const directiveNodes = this.spreadDirectives.length === 0
1487
1752
  ? undefined
1488
- : spreadDirectives.map(directive => {
1753
+ : this.spreadDirectives.map(directive => {
1489
1754
  return {
1490
1755
  kind: graphql_1.Kind.DIRECTIVE,
1491
1756
  name: {
@@ -1504,20 +1769,26 @@ class FragmentSpreadSelection extends FragmentSelection {
1504
1769
  optimize(_) {
1505
1770
  return this;
1506
1771
  }
1507
- updateForAddingTo(_selectionSet) {
1772
+ rebaseOn(_parentType) {
1508
1773
  return this;
1509
1774
  }
1510
1775
  canAddTo(_) {
1511
1776
  return true;
1512
1777
  }
1513
- expandFragments(names, updateSelectionSetFragments = true) {
1514
- if (names && !names.includes(this.namedFragment.name)) {
1778
+ expandAllFragments() {
1779
+ const expandedSubSelections = this.selectionSet.expandAllFragments();
1780
+ return (0, types_1.sameType)(this.parentType, this.namedFragment.typeCondition) && this.element.appliedDirectives.length === 0
1781
+ ? expandedSubSelections.selections()
1782
+ : new InlineFragmentSelection(this.element, expandedSubSelections);
1783
+ }
1784
+ expandFragments(names, updatedFragments) {
1785
+ if (!names.includes(this.namedFragment.name)) {
1515
1786
  return this;
1516
1787
  }
1517
- const expandedSubSelections = this.selectionSet.expandFragments(names, updateSelectionSetFragments);
1518
- return (0, types_1.sameType)(this._element.parentType, this.namedFragment.typeCondition) && this._element.appliedDirectives.length === 0
1788
+ const expandedSubSelections = this.selectionSet.expandFragments(names, updatedFragments);
1789
+ return (0, types_1.sameType)(this.parentType, this.namedFragment.typeCondition) && this.element.appliedDirectives.length === 0
1519
1790
  ? expandedSubSelections.selections()
1520
- : new InlineFragmentSelection(this._element, expandedSubSelections);
1791
+ : new InlineFragmentSelection(this.element, expandedSubSelections);
1521
1792
  }
1522
1793
  collectUsedFragmentNames(collector) {
1523
1794
  this.selectionSet.collectUsedFragmentNames(collector);
@@ -1525,28 +1796,89 @@ class FragmentSpreadSelection extends FragmentSelection {
1525
1796
  collector.set(this.namedFragment.name, usageCount === undefined ? 1 : usageCount + 1);
1526
1797
  }
1527
1798
  withoutDefer(_labelsToRemove) {
1528
- (0, utils_1.assert)(false, 'Unsupported, see `Operation.withoutDefer`');
1799
+ (0, utils_1.assert)(false, 'Unsupported, see `Operation.withAllDeferLabelled`');
1529
1800
  }
1530
- withNormalizedDefer(_normalizezr) {
1801
+ withNormalizedDefer(_normalizer) {
1531
1802
  (0, utils_1.assert)(false, 'Unsupported, see `Operation.withAllDeferLabelled`');
1532
1803
  }
1533
- spreadDirectives() {
1534
- return this._element.appliedDirectives.slice(this.namedFragment.appliedDirectives.length);
1804
+ minus(that) {
1805
+ (0, utils_1.assert)(this.equals(that), () => `Invalid operation for ${this.toString(false)} and ${that.toString(false)}`);
1806
+ return undefined;
1807
+ }
1808
+ equals(that) {
1809
+ if (this === that) {
1810
+ return true;
1811
+ }
1812
+ return (that instanceof FragmentSpreadSelection)
1813
+ && this.namedFragment.name === that.namedFragment.name
1814
+ && (0, definitions_1.sameDirectiveApplications)(this.spreadDirectives, that.spreadDirectives);
1535
1815
  }
1536
- withUpdatedSubSelection(_) {
1537
- (0, utils_1.assert)(false, `Unssupported`);
1816
+ contains(that) {
1817
+ if (this.equals(that)) {
1818
+ return true;
1819
+ }
1820
+ return (that instanceof FragmentSelection)
1821
+ && this.element.equals(that.element)
1822
+ && this.selectionSet.contains(that.selectionSet);
1538
1823
  }
1539
1824
  toString(expandFragments = true, indent) {
1540
1825
  if (expandFragments) {
1541
- return (indent !== null && indent !== void 0 ? indent : '') + this._element + ' ' + this.selectionSet.toString(true, true, indent);
1826
+ return (indent !== null && indent !== void 0 ? indent : '') + this.element + ' ' + this.selectionSet.toString(true, true, indent);
1542
1827
  }
1543
1828
  else {
1544
- const directives = this.spreadDirectives();
1829
+ const directives = this.spreadDirectives;
1545
1830
  const directiveString = directives.length == 0 ? '' : ' ' + directives.join(' ');
1546
1831
  return (indent !== null && indent !== void 0 ? indent : '') + '...' + this.namedFragment.name + directiveString;
1547
1832
  }
1548
1833
  }
1549
1834
  }
1835
+ function selectionSetOfNode(parentType, node, variableDefinitions, fragments, fieldAccessor = (type, name) => type.field(name)) {
1836
+ if (node.selections.length === 1) {
1837
+ return selectionSetOf(parentType, selectionOfNode(parentType, node.selections[0], variableDefinitions, fragments, fieldAccessor), fragments);
1838
+ }
1839
+ const selections = new SelectionSetUpdates();
1840
+ for (const selectionNode of node.selections) {
1841
+ selections.add(selectionOfNode(parentType, selectionNode, variableDefinitions, fragments, fieldAccessor));
1842
+ }
1843
+ return selections.toSelectionSet(parentType, fragments);
1844
+ }
1845
+ function directiveOfNode(schema, node) {
1846
+ const directiveDef = schema.directive(node.name.value);
1847
+ validate(directiveDef, () => `Unknown directive "@${node.name.value}"`);
1848
+ return new definitions_1.Directive(directiveDef.name, (0, values_1.argumentsFromAST)(directiveDef.coordinate, node.arguments, directiveDef));
1849
+ }
1850
+ function directivesOfNodes(schema, nodes) {
1851
+ var _a;
1852
+ return (_a = nodes === null || nodes === void 0 ? void 0 : nodes.map((n) => directiveOfNode(schema, n))) !== null && _a !== void 0 ? _a : [];
1853
+ }
1854
+ function selectionOfNode(parentType, node, variableDefinitions, fragments, fieldAccessor = (type, name) => type.field(name)) {
1855
+ var _a, _b;
1856
+ let selection;
1857
+ const directives = directivesOfNodes(parentType.schema(), node.directives);
1858
+ switch (node.kind) {
1859
+ case graphql_1.Kind.FIELD:
1860
+ const definition = fieldAccessor(parentType, node.name.value);
1861
+ validate(definition, () => `Cannot query field "${node.name.value}" on type "${parentType}".`, parentType.sourceAST);
1862
+ const type = (0, definitions_1.baseType)(definition.type);
1863
+ const selectionSet = node.selectionSet
1864
+ ? selectionSetOfNode(type, node.selectionSet, variableDefinitions, fragments, fieldAccessor)
1865
+ : undefined;
1866
+ selection = new FieldSelection(new Field(definition, (0, values_1.argumentsFromAST)(definition.coordinate, node.arguments, definition), directives, (_a = node.alias) === null || _a === void 0 ? void 0 : _a.value), selectionSet);
1867
+ break;
1868
+ case graphql_1.Kind.INLINE_FRAGMENT:
1869
+ const element = new FragmentElement(parentType, (_b = node.typeCondition) === null || _b === void 0 ? void 0 : _b.name.value, directives);
1870
+ selection = new InlineFragmentSelection(element, selectionSetOfNode(element.typeCondition ? element.typeCondition : element.parentType, node.selectionSet, variableDefinitions, fragments, fieldAccessor));
1871
+ break;
1872
+ case graphql_1.Kind.FRAGMENT_SPREAD:
1873
+ const fragmentName = node.name.value;
1874
+ validate(fragments, () => `Cannot find fragment name "${fragmentName}" (no fragments were provided)`);
1875
+ const fragment = fragments.get(fragmentName);
1876
+ validate(fragment, () => `Cannot find fragment name "${fragmentName}" (provided fragments are: [${fragments.names().join(', ')}])`);
1877
+ selection = new FragmentSpreadSelection(parentType, fragments, fragment, directives);
1878
+ break;
1879
+ }
1880
+ return selection;
1881
+ }
1550
1882
  function operationFromDocument(schema, document, options) {
1551
1883
  let operation;
1552
1884
  const operationName = options === null || options === void 0 ? void 0 : options.operationName;
@@ -1569,9 +1901,7 @@ function operationFromDocument(schema, document, options) {
1569
1901
  if (!(0, definitions_1.isCompositeType)(typeCondition)) {
1570
1902
  throw error_1.ERRORS.INVALID_GRAPHQL.err(`Invalid fragment "${name}" on non-composite type "${typeName}"`, { nodes: definition });
1571
1903
  }
1572
- const fragment = new NamedFragmentDefinition(schema, name, typeCondition, new SelectionSet(typeCondition, fragments));
1573
- addDirectiveNodesToElement(definition.directives, fragment);
1574
- fragments.add(fragment);
1904
+ fragments.add(new NamedFragmentDefinition(schema, name, typeCondition, directivesOfNodes(schema, definition.directives)));
1575
1905
  break;
1576
1906
  }
1577
1907
  });
@@ -1583,11 +1913,11 @@ function operationFromDocument(schema, document, options) {
1583
1913
  switch (definition.kind) {
1584
1914
  case graphql_1.Kind.FRAGMENT_DEFINITION:
1585
1915
  const fragment = fragments.get(definition.name.value);
1586
- fragment.selectionSet.addSelectionSetNode(definition.selectionSet, variableDefinitions);
1916
+ fragment.setSelectionSet(selectionSetOfNode(fragment.typeCondition, definition.selectionSet, variableDefinitions, fragments));
1587
1917
  break;
1588
1918
  }
1589
1919
  });
1590
- fragments.validate();
1920
+ fragments.validate(variableDefinitions);
1591
1921
  return operationFromAST({ schema, operation, variableDefinitions, fragments, validateInput: options === null || options === void 0 ? void 0 : options.validate });
1592
1922
  }
1593
1923
  exports.operationFromDocument = operationFromDocument;
@@ -1599,7 +1929,7 @@ function operationFromAST({ schema, operation, variableDefinitions, fragments, v
1599
1929
  parentType: rootType.type,
1600
1930
  source: operation.selectionSet,
1601
1931
  variableDefinitions,
1602
- fragments,
1932
+ fragments: fragments.isEmpty() ? undefined : fragments,
1603
1933
  validate: validateInput,
1604
1934
  }), variableDefinitions, (_a = operation.name) === null || _a === void 0 ? void 0 : _a.value);
1605
1935
  }
@@ -1607,14 +1937,13 @@ function parseOperation(schema, operation, options) {
1607
1937
  return operationFromDocument(schema, (0, graphql_1.parse)(operation), options);
1608
1938
  }
1609
1939
  exports.parseOperation = parseOperation;
1610
- function parseSelectionSet({ parentType, source, variableDefinitions, fragments, fieldAccessor, validate = true, }) {
1940
+ function parseSelectionSet({ parentType, source, variableDefinitions = new definitions_1.VariableDefinitions(), fragments, fieldAccessor, validate = true, }) {
1611
1941
  const node = typeof source === 'string'
1612
1942
  ? parseOperationAST(source.trim().startsWith('{') ? source : `{${source}}`).selectionSet
1613
1943
  : source;
1614
- const selectionSet = new SelectionSet(parentType, fragments);
1615
- selectionSet.addSelectionSetNode(node, variableDefinitions !== null && variableDefinitions !== void 0 ? variableDefinitions : new definitions_1.VariableDefinitions(), fieldAccessor);
1944
+ const selectionSet = selectionSetOfNode(parentType, node, variableDefinitions !== null && variableDefinitions !== void 0 ? variableDefinitions : new definitions_1.VariableDefinitions(), fragments, fieldAccessor);
1616
1945
  if (validate)
1617
- selectionSet.validate();
1946
+ selectionSet.validate(variableDefinitions);
1618
1947
  return selectionSet;
1619
1948
  }
1620
1949
  exports.parseSelectionSet = parseSelectionSet;