@apollo/federation-internals 2.4.1 → 2.4.3
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.
- package/CHANGELOG.md +21 -0
- package/dist/argumentCompositionStrategies.d.ts +34 -0
- package/dist/argumentCompositionStrategies.d.ts.map +1 -0
- package/dist/argumentCompositionStrategies.js +35 -0
- package/dist/argumentCompositionStrategies.js.map +1 -0
- package/dist/coreSpec.d.ts +12 -3
- package/dist/coreSpec.d.ts.map +1 -1
- package/dist/coreSpec.js +68 -17
- package/dist/coreSpec.js.map +1 -1
- package/dist/definitions.d.ts +1 -0
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +30 -27
- package/dist/definitions.js.map +1 -1
- package/dist/directiveAndTypeSpecification.d.ts +26 -7
- package/dist/directiveAndTypeSpecification.d.ts.map +1 -1
- package/dist/directiveAndTypeSpecification.js +56 -4
- package/dist/directiveAndTypeSpecification.js.map +1 -1
- package/dist/federation.d.ts.map +1 -1
- package/dist/federation.js +24 -2
- package/dist/federation.js.map +1 -1
- package/dist/federationSpec.d.ts +2 -13
- package/dist/federationSpec.d.ts.map +1 -1
- package/dist/federationSpec.js +10 -60
- package/dist/federationSpec.js.map +1 -1
- package/dist/inaccessibleSpec.d.ts +0 -2
- package/dist/inaccessibleSpec.d.ts.map +1 -1
- package/dist/inaccessibleSpec.js +3 -6
- package/dist/inaccessibleSpec.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/knownCoreFeatures.d.ts +1 -0
- package/dist/knownCoreFeatures.d.ts.map +1 -1
- package/dist/knownCoreFeatures.js +5 -1
- package/dist/knownCoreFeatures.js.map +1 -1
- package/dist/operations.d.ts +18 -6
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +102 -37
- package/dist/operations.js.map +1 -1
- package/dist/print.d.ts +7 -1
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +33 -5
- package/dist/print.js.map +1 -1
- package/dist/tagSpec.d.ts +0 -2
- package/dist/tagSpec.d.ts.map +1 -1
- package/dist/tagSpec.js +4 -10
- package/dist/tagSpec.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/directiveAndTypeSpecifications.test.ts +41 -0
- package/src/__tests__/operations.test.ts +175 -10
- package/src/argumentCompositionStrategies.ts +39 -0
- package/src/coreSpec.ts +94 -34
- package/src/definitions.ts +35 -29
- package/src/directiveAndTypeSpecification.ts +101 -14
- package/src/federation.ts +33 -4
- package/src/federationSpec.ts +13 -73
- package/src/inaccessibleSpec.ts +4 -11
- package/src/index.ts +3 -0
- package/src/knownCoreFeatures.ts +9 -0
- package/src/operations.ts +198 -40
- package/src/print.ts +39 -4
- package/src/tagSpec.ts +4 -12
- package/tsconfig.tsbuildinfo +1 -1
package/dist/operations.js
CHANGED
|
@@ -437,7 +437,7 @@ function isUselessFollowupElement(first, followup, conditionals) {
|
|
|
437
437
|
&& followup.kind === 'FragmentElement'
|
|
438
438
|
&& !!followup.typeCondition
|
|
439
439
|
&& (followup.appliedDirectives.length === 0 || (0, definitions_1.isDirectiveApplicationsSubset)(conditionals, followup.appliedDirectives))
|
|
440
|
-
&& (0, types_1.
|
|
440
|
+
&& (0, types_1.isSubtype)(followup.typeCondition, typeOfFirst);
|
|
441
441
|
}
|
|
442
442
|
class Operation {
|
|
443
443
|
constructor(schema, rootKind, selectionSet, variableDefinitions, name) {
|
|
@@ -465,8 +465,11 @@ class Operation {
|
|
|
465
465
|
}
|
|
466
466
|
}
|
|
467
467
|
const toDeoptimize = (0, utils_1.mapEntries)(usages).filter(([_, count]) => count < minUsagesToOptimize).map(([name]) => name);
|
|
468
|
-
|
|
469
|
-
|
|
468
|
+
if (toDeoptimize.length > 0) {
|
|
469
|
+
const newFragments = (_a = optimizedSelection.fragments) === null || _a === void 0 ? void 0 : _a.without(toDeoptimize);
|
|
470
|
+
optimizedSelection = optimizedSelection.expandFragments(toDeoptimize, newFragments);
|
|
471
|
+
optimizedSelection = optimizedSelection.trimUnsatisfiableBranches(optimizedSelection.parentType);
|
|
472
|
+
}
|
|
470
473
|
return new Operation(this.schema, this.rootKind, optimizedSelection, this.variableDefinitions, this.name);
|
|
471
474
|
}
|
|
472
475
|
expandAllFragments() {
|
|
@@ -525,9 +528,11 @@ class NamedFragmentDefinition extends definitions_1.DirectiveTargetElement {
|
|
|
525
528
|
super(schema, directives);
|
|
526
529
|
this.name = name;
|
|
527
530
|
this.typeCondition = typeCondition;
|
|
531
|
+
this.selectionSetsAtTypesCache = new Map();
|
|
528
532
|
}
|
|
529
533
|
setSelectionSet(selectionSet) {
|
|
530
534
|
(0, utils_1.assert)(!this._selectionSet, 'Attempting to set the selection set of a fragment definition already built');
|
|
535
|
+
(0, utils_1.assert)(selectionSet.parentType === this.typeCondition, `Fragment selection set parent is ${selectionSet.parentType} differs from the fragment condition type ${this.typeCondition}`);
|
|
531
536
|
this._selectionSet = selectionSet;
|
|
532
537
|
return this;
|
|
533
538
|
}
|
|
@@ -559,25 +564,21 @@ class NamedFragmentDefinition extends definitions_1.DirectiveTargetElement {
|
|
|
559
564
|
};
|
|
560
565
|
}
|
|
561
566
|
canApplyAtType(type) {
|
|
562
|
-
|
|
563
|
-
return applyAtType
|
|
564
|
-
&& this.validForSchema(type.schema());
|
|
567
|
+
return (0, types_1.sameType)(type, this.typeCondition) || (0, definitions_1.runtimeTypesIntersects)(type, this.typeCondition);
|
|
565
568
|
}
|
|
566
|
-
|
|
567
|
-
if (
|
|
568
|
-
return
|
|
569
|
+
selectionSetAtType(type) {
|
|
570
|
+
if ((0, types_1.sameType)(type, this.typeCondition) || (0, definitions_1.isObjectType)(this.typeCondition)) {
|
|
571
|
+
return this.selectionSet;
|
|
569
572
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
return false;
|
|
573
|
+
if (!(0, definitions_1.isObjectType)(type)) {
|
|
574
|
+
return this.selectionSet;
|
|
573
575
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
catch (e) {
|
|
579
|
-
return false;
|
|
576
|
+
let selectionSet = this.selectionSetsAtTypesCache.get(type.name);
|
|
577
|
+
if (!selectionSet) {
|
|
578
|
+
selectionSet = this.selectionSet.trimUnsatisfiableBranches(type, { recursive: false });
|
|
579
|
+
this.selectionSetsAtTypesCache.set(type.name, selectionSet);
|
|
580
580
|
}
|
|
581
|
+
return selectionSet;
|
|
581
582
|
}
|
|
582
583
|
toString(indent) {
|
|
583
584
|
return (indent !== null && indent !== void 0 ? indent : '') + `fragment ${this.name} on ${this.typeCondition}${this.appliedDirectivesToString()} ${this.selectionSet.toString(false, true, indent)}`;
|
|
@@ -640,6 +641,46 @@ class NamedFragments {
|
|
|
640
641
|
}
|
|
641
642
|
return mapped;
|
|
642
643
|
}
|
|
644
|
+
mapToExpandedSelectionSets(mapper, recreateFct = (f, s) => f.withUpdatedSelectionSet(s)) {
|
|
645
|
+
const fragmentsMap = new Map();
|
|
646
|
+
const removedFragments = new Set();
|
|
647
|
+
for (const fragment of this.definitions()) {
|
|
648
|
+
const mappedSelectionSet = mapper(fragment.selectionSet.expandAllFragments().trimUnsatisfiableBranches(fragment.typeCondition));
|
|
649
|
+
if (!mappedSelectionSet) {
|
|
650
|
+
removedFragments.add(fragment.name);
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
const otherFragmentsUsages = new Map();
|
|
654
|
+
fragment.collectUsedFragmentNames(otherFragmentsUsages);
|
|
655
|
+
fragmentsMap.set(fragment.name, {
|
|
656
|
+
original: fragment,
|
|
657
|
+
mappedSelectionSet,
|
|
658
|
+
dependsOn: Array.from(otherFragmentsUsages.keys()),
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
const mappedFragments = new NamedFragments();
|
|
662
|
+
while (fragmentsMap.size > 0) {
|
|
663
|
+
for (const [name, info] of fragmentsMap) {
|
|
664
|
+
if (info.dependsOn.every((n) => mappedFragments.has(n) || removedFragments.has(n))) {
|
|
665
|
+
const reoptimizedSelectionSet = info.mappedSelectionSet.optimize(mappedFragments);
|
|
666
|
+
mappedFragments.add(recreateFct(info.original, reoptimizedSelectionSet));
|
|
667
|
+
fragmentsMap.delete(name);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
return mappedFragments.isEmpty() ? undefined : mappedFragments;
|
|
672
|
+
}
|
|
673
|
+
rebaseOn(schema) {
|
|
674
|
+
return this.mapToExpandedSelectionSets((s) => {
|
|
675
|
+
const rebasedType = schema.type(s.parentType.name);
|
|
676
|
+
try {
|
|
677
|
+
return rebasedType && (0, definitions_1.isCompositeType)(rebasedType) ? s.rebaseOn(rebasedType) : undefined;
|
|
678
|
+
}
|
|
679
|
+
catch (e) {
|
|
680
|
+
return undefined;
|
|
681
|
+
}
|
|
682
|
+
}, (orig, newSelection) => new NamedFragmentDefinition(schema, orig.name, newSelection.parentType).setSelectionSet(newSelection));
|
|
683
|
+
}
|
|
643
684
|
validate(variableDefinitions) {
|
|
644
685
|
for (const fragment of this.fragments.values()) {
|
|
645
686
|
fragment.selectionSet.validate(variableDefinitions);
|
|
@@ -755,6 +796,13 @@ class SelectionSet {
|
|
|
755
796
|
if (!fragments || fragments.isEmpty()) {
|
|
756
797
|
return this;
|
|
757
798
|
}
|
|
799
|
+
const wrapped = new InlineFragmentSelection(new FragmentElement(this.parentType, this.parentType), this);
|
|
800
|
+
const optimized = wrapped.optimize(fragments);
|
|
801
|
+
return optimized instanceof FragmentSpreadSelection
|
|
802
|
+
? selectionSetOf(this.parentType, optimized, fragments)
|
|
803
|
+
: optimized.selectionSet;
|
|
804
|
+
}
|
|
805
|
+
optimizeSelections(fragments) {
|
|
758
806
|
(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
807
|
return this.lazyMap((selection) => selection.optimize(fragments), { fragments });
|
|
760
808
|
}
|
|
@@ -767,8 +815,8 @@ class SelectionSet {
|
|
|
767
815
|
}
|
|
768
816
|
return this.lazyMap((selection) => selection.expandFragments(names, updatedFragments), { fragments: updatedFragments !== null && updatedFragments !== void 0 ? updatedFragments : null });
|
|
769
817
|
}
|
|
770
|
-
trimUnsatisfiableBranches(parentType) {
|
|
771
|
-
return this.lazyMap((selection) => selection.trimUnsatisfiableBranches(parentType), { parentType });
|
|
818
|
+
trimUnsatisfiableBranches(parentType, options) {
|
|
819
|
+
return this.lazyMap((selection) => selection.trimUnsatisfiableBranches(parentType, options), { parentType });
|
|
772
820
|
}
|
|
773
821
|
lazyMap(mapper, options) {
|
|
774
822
|
var _a;
|
|
@@ -881,9 +929,14 @@ class SelectionSet {
|
|
|
881
929
|
}
|
|
882
930
|
return true;
|
|
883
931
|
}
|
|
884
|
-
|
|
932
|
+
diffWithNamedFragmentIfContained(candidate, parentType) {
|
|
933
|
+
const that = candidate.selectionSetAtType(parentType);
|
|
885
934
|
if (this.contains(that)) {
|
|
886
|
-
|
|
935
|
+
let updatedThis = this.expandFragments([candidate.name], this.fragments);
|
|
936
|
+
if (updatedThis !== this) {
|
|
937
|
+
updatedThis = updatedThis.trimUnsatisfiableBranches(parentType);
|
|
938
|
+
}
|
|
939
|
+
const diff = updatedThis.minus(that);
|
|
887
940
|
return { contains: true, diff: diff.isEmpty() ? undefined : diff };
|
|
888
941
|
}
|
|
889
942
|
return { contains: false };
|
|
@@ -1069,9 +1122,17 @@ function addOneToKeyedUpdates(keyedUpdates, selection) {
|
|
|
1069
1122
|
keyedUpdates.add(selection.key(), selection);
|
|
1070
1123
|
}
|
|
1071
1124
|
}
|
|
1125
|
+
function maybeRebaseOnSchema(toRebase, schema) {
|
|
1126
|
+
if (toRebase.schema() === schema) {
|
|
1127
|
+
return toRebase;
|
|
1128
|
+
}
|
|
1129
|
+
const rebased = schema.type(toRebase.name);
|
|
1130
|
+
(0, utils_1.assert)(rebased && (0, definitions_1.isCompositeType)(rebased), () => `Expected ${toRebase} to exists and be composite in the rebased schema, but got ${rebased === null || rebased === void 0 ? void 0 : rebased.kind}`);
|
|
1131
|
+
return rebased;
|
|
1132
|
+
}
|
|
1072
1133
|
function isUnecessaryFragment(parentType, fragment) {
|
|
1073
1134
|
return fragment.element.appliedDirectives.length === 0
|
|
1074
|
-
&& (!fragment.element.typeCondition || (0, types_1.
|
|
1135
|
+
&& (!fragment.element.typeCondition || (0, types_1.isSubtype)(maybeRebaseOnSchema(fragment.element.typeCondition, parentType.schema()), parentType));
|
|
1075
1136
|
}
|
|
1076
1137
|
function withUnecessaryFragmentsRemoved(parentType, selections) {
|
|
1077
1138
|
if (selections instanceof AbstractSelection) {
|
|
@@ -1321,7 +1382,7 @@ class FieldSelection extends AbstractSelection {
|
|
|
1321
1382
|
return this.element.key();
|
|
1322
1383
|
}
|
|
1323
1384
|
optimize(fragments) {
|
|
1324
|
-
let optimizedSelection = this.selectionSet ? this.selectionSet.
|
|
1385
|
+
let optimizedSelection = this.selectionSet ? this.selectionSet.optimizeSelections(fragments) : undefined;
|
|
1325
1386
|
const fieldBaseType = (0, definitions_1.baseType)(this.element.definition.type);
|
|
1326
1387
|
if ((0, definitions_1.isCompositeType)(fieldBaseType) && optimizedSelection) {
|
|
1327
1388
|
const optimized = this.tryOptimizeSubselectionWithFragments({
|
|
@@ -1340,7 +1401,7 @@ class FieldSelection extends AbstractSelection {
|
|
|
1340
1401
|
tryOptimizeSubselectionOnce({ parentType, subSelection, candidates, fragments, }) {
|
|
1341
1402
|
let optimizedSelection = subSelection;
|
|
1342
1403
|
for (const candidate of candidates) {
|
|
1343
|
-
const { contains, diff } = optimizedSelection.
|
|
1404
|
+
const { contains, diff } = optimizedSelection.diffWithNamedFragmentIfContained(candidate, parentType);
|
|
1344
1405
|
if (contains) {
|
|
1345
1406
|
const spread = new FragmentSpreadSelection(parentType, fragments, candidate, []);
|
|
1346
1407
|
optimizedSelection = diff
|
|
@@ -1425,15 +1486,15 @@ class FieldSelection extends AbstractSelection {
|
|
|
1425
1486
|
expandAllFragments() {
|
|
1426
1487
|
return this.mapToSelectionSet((s) => s.expandAllFragments());
|
|
1427
1488
|
}
|
|
1428
|
-
trimUnsatisfiableBranches(_) {
|
|
1429
|
-
var _a;
|
|
1489
|
+
trimUnsatisfiableBranches(_, options) {
|
|
1490
|
+
var _a, _b;
|
|
1430
1491
|
if (!this.selectionSet) {
|
|
1431
1492
|
return this;
|
|
1432
1493
|
}
|
|
1433
1494
|
const base = (0, definitions_1.baseType)(this.element.definition.type);
|
|
1434
1495
|
(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 ((
|
|
1496
|
+
const trimmed = ((_a = options === null || options === void 0 ? void 0 : options.recursive) !== null && _a !== void 0 ? _a : true) ? this.mapToSelectionSet((s) => s.trimUnsatisfiableBranches(base)) : this;
|
|
1497
|
+
if ((_b = trimmed.selectionSet) === null || _b === void 0 ? void 0 : _b.isEmpty()) {
|
|
1437
1498
|
return trimmed.withUpdatedSelectionSet(selectionSetOfElement(new Field(base.typenameField(), undefined, [new definitions_1.Directive('include', { 'if': false })])));
|
|
1438
1499
|
}
|
|
1439
1500
|
else {
|
|
@@ -1567,7 +1628,7 @@ class InlineFragmentSelection extends FragmentSelection {
|
|
|
1567
1628
|
};
|
|
1568
1629
|
}
|
|
1569
1630
|
optimize(fragments) {
|
|
1570
|
-
let optimizedSelection = this.selectionSet.
|
|
1631
|
+
let optimizedSelection = this.selectionSet.optimizeSelections(fragments);
|
|
1571
1632
|
const typeCondition = this.element.typeCondition;
|
|
1572
1633
|
if (typeCondition) {
|
|
1573
1634
|
const optimized = this.tryOptimizeSubselectionWithFragments({
|
|
@@ -1587,7 +1648,7 @@ class InlineFragmentSelection extends FragmentSelection {
|
|
|
1587
1648
|
tryOptimizeSubselectionOnce({ parentType, subSelection, candidates, fragments, }) {
|
|
1588
1649
|
let optimizedSelection = subSelection;
|
|
1589
1650
|
for (const candidate of candidates) {
|
|
1590
|
-
const { contains, diff } = optimizedSelection.
|
|
1651
|
+
const { contains, diff } = optimizedSelection.diffWithNamedFragmentIfContained(candidate, parentType);
|
|
1591
1652
|
if (contains) {
|
|
1592
1653
|
if (!diff && (0, types_1.sameType)(this.element.typeCondition, candidate.typeCondition)) {
|
|
1593
1654
|
let spreadDirectives = this.element.appliedDirectives;
|
|
@@ -1637,12 +1698,13 @@ class InlineFragmentSelection extends FragmentSelection {
|
|
|
1637
1698
|
? this
|
|
1638
1699
|
: this.withUpdatedComponents(newElement, newSelection);
|
|
1639
1700
|
}
|
|
1640
|
-
trimUnsatisfiableBranches(currentType) {
|
|
1641
|
-
var _a, _b;
|
|
1701
|
+
trimUnsatisfiableBranches(currentType, options) {
|
|
1702
|
+
var _a, _b, _c;
|
|
1703
|
+
const recursive = (_a = options === null || options === void 0 ? void 0 : options.recursive) !== null && _a !== void 0 ? _a : true;
|
|
1642
1704
|
const thisCondition = this.element.typeCondition;
|
|
1643
1705
|
if (this.element.appliedDirectives.length === 0) {
|
|
1644
1706
|
if (!thisCondition || currentType === this.element.typeCondition) {
|
|
1645
|
-
const trimmed = this.selectionSet.trimUnsatisfiableBranches(currentType);
|
|
1707
|
+
const trimmed = this.selectionSet.trimUnsatisfiableBranches(currentType, options);
|
|
1646
1708
|
return trimmed.isEmpty() ? undefined : trimmed;
|
|
1647
1709
|
}
|
|
1648
1710
|
if ((0, definitions_1.isObjectType)(currentType)) {
|
|
@@ -1650,18 +1712,21 @@ class InlineFragmentSelection extends FragmentSelection {
|
|
|
1650
1712
|
return undefined;
|
|
1651
1713
|
}
|
|
1652
1714
|
else {
|
|
1653
|
-
const trimmed = this.selectionSet.trimUnsatisfiableBranches(currentType);
|
|
1715
|
+
const trimmed = this.selectionSet.trimUnsatisfiableBranches(currentType, options);
|
|
1654
1716
|
return trimmed.isEmpty() ? undefined : trimmed;
|
|
1655
1717
|
}
|
|
1656
1718
|
}
|
|
1657
1719
|
}
|
|
1658
|
-
|
|
1720
|
+
if (!recursive) {
|
|
1721
|
+
return this;
|
|
1722
|
+
}
|
|
1723
|
+
const trimmedSelectionSet = this.selectionSet.trimUnsatisfiableBranches((_b = this.element.typeCondition) !== null && _b !== void 0 ? _b : this.parentType);
|
|
1659
1724
|
if (trimmedSelectionSet.isEmpty()) {
|
|
1660
1725
|
if (this.element.appliedDirectives.length === 0) {
|
|
1661
1726
|
return undefined;
|
|
1662
1727
|
}
|
|
1663
1728
|
else {
|
|
1664
|
-
return this.withUpdatedSelectionSet(selectionSetOfElement(new Field(((
|
|
1729
|
+
return this.withUpdatedSelectionSet(selectionSetOfElement(new Field(((_c = this.element.typeCondition) !== null && _c !== void 0 ? _c : this.parentType).typenameField(), undefined, [new definitions_1.Directive('include', { 'if': false })])));
|
|
1665
1730
|
}
|
|
1666
1731
|
}
|
|
1667
1732
|
if (this.element.appliedDirectives.length === 0 && (0, definitions_1.isAbstractType)(thisCondition)) {
|