@apollo/query-graphs
Version:
Apollo Federation library to work with 'query graphs'
623 lines • 32.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NonLocalSelectionsState = exports.NonLocalSelectionsMetadata = void 0;
const federation_internals_1 = require("@apollo/federation-internals");
const querygraph_1 = require("./querygraph");
;
class NonLocalSelectionsMetadata {
constructor(graph) {
this.typesToIndirectOptions = new Map();
this.remainingVerticesToInterfaceObjectOptions = new Map;
this.fieldsToEndpoints = new Map();
this.inlineFragmentsToEndpoints = new Map();
this.verticesToObjectTypeDowncasts = new Map();
this.fieldsToRebaseableParentVertices = new Map;
this.inlineFragmentsToRebaseableParentVertices = new Map;
this.precomputeNonLocalSelectionMetadata(graph);
}
precomputeNonLocalSelectionMetadata(graph) {
this.precomputeNextVertexMetadata(graph);
this.precomputeRebasingMetadata(graph);
}
precomputeNextVertexMetadata(graph) {
const verticesToInterfaceObjectOptions = new Map();
for (const edge of graph.allEdges()) {
switch (edge.transition.kind) {
case 'FieldCollection': {
if (!(0, federation_internals_1.isCompositeType)(edge.tail.type)) {
continue;
}
const fieldName = edge.transition.definition.name;
let endpointsEntry = this.fieldsToEndpoints.get(fieldName);
if (!endpointsEntry) {
endpointsEntry = new Map();
this.fieldsToEndpoints.set(fieldName, endpointsEntry);
}
endpointsEntry.set(edge.head, {
tail: edge.tail,
overrideCondition: edge.overrideCondition
});
break;
}
case 'DownCast': {
if ((0, federation_internals_1.isObjectType)(edge.transition.castedType)) {
let downcastsEntry = this.verticesToObjectTypeDowncasts.get(edge.head);
if (!downcastsEntry) {
downcastsEntry = {
kind: 'NonInterfaceObject',
downcasts: new Map(),
};
this.verticesToObjectTypeDowncasts.set(edge.head, downcastsEntry);
}
(0, federation_internals_1.assert)(downcastsEntry.kind === 'NonInterfaceObject', () => 'Unexpectedly found interface object with regular object downcasts');
downcastsEntry.downcasts.set(edge.transition.castedType.name, edge.tail);
}
const typeConditionName = edge.transition.castedType.name;
let endpointsEntry = this.inlineFragmentsToEndpoints
.get(typeConditionName);
if (!endpointsEntry) {
endpointsEntry = new Map();
this.inlineFragmentsToEndpoints.set(typeConditionName, endpointsEntry);
}
endpointsEntry.set(edge.head, edge.tail);
break;
}
case 'InterfaceObjectFakeDownCast': {
let downcastsEntry = this.verticesToObjectTypeDowncasts.get(edge.head);
if (!downcastsEntry) {
downcastsEntry = {
kind: 'InterfaceObject',
downcasts: new Set(),
};
this.verticesToObjectTypeDowncasts.set(edge.head, downcastsEntry);
}
(0, federation_internals_1.assert)(downcastsEntry.kind === 'InterfaceObject', () => 'Unexpectedly found abstract type with interface object downcasts');
downcastsEntry.downcasts.add(edge.transition.castedTypeName);
const typeConditionName = edge.transition.castedTypeName;
let endpointsEntry = this.inlineFragmentsToEndpoints
.get(typeConditionName);
if (!endpointsEntry) {
endpointsEntry = new Map();
this.inlineFragmentsToEndpoints.set(typeConditionName, endpointsEntry);
}
endpointsEntry.set(edge.head, edge.tail);
break;
}
case 'KeyResolution':
case 'RootTypeResolution': {
const headTypeName = edge.head.type.name;
const tailTypeName = edge.tail.type.name;
if (headTypeName === tailTypeName) {
let indirectOptionsEntry = this.typesToIndirectOptions
.get(tailTypeName);
if (!indirectOptionsEntry) {
indirectOptionsEntry = {
sameTypeOptions: new Set(),
interfaceObjectOptions: new Set(),
};
this.typesToIndirectOptions.set(tailTypeName, indirectOptionsEntry);
}
indirectOptionsEntry.sameTypeOptions.add(edge.tail);
}
else {
let interfaceObjectOptionsEntry = verticesToInterfaceObjectOptions
.get(edge.head);
if (!interfaceObjectOptionsEntry) {
interfaceObjectOptionsEntry = new Set();
verticesToInterfaceObjectOptions.set(edge.head, interfaceObjectOptionsEntry);
}
interfaceObjectOptionsEntry.add(tailTypeName);
}
break;
}
case 'SubgraphEnteringTransition':
break;
default:
(0, federation_internals_1.assertUnreachable)(edge.transition);
}
}
for (const [vertex, options] of verticesToInterfaceObjectOptions) {
const optionsMetadata = this.typesToIndirectOptions.get(vertex.type.name);
if (optionsMetadata) {
if (optionsMetadata.sameTypeOptions.has(vertex)) {
for (const option of options) {
optionsMetadata.interfaceObjectOptions.add(option);
}
continue;
}
}
this.remainingVerticesToInterfaceObjectOptions.set(vertex, options);
}
for (const [vertex, options] of this.remainingVerticesToInterfaceObjectOptions) {
const indirectOptionsMetadata = this.typesToIndirectOptions
.get(vertex.type.name);
if (!indirectOptionsMetadata) {
continue;
}
for (const option of options) {
if (indirectOptionsMetadata.interfaceObjectOptions.has(option)) {
options.delete(option);
}
}
if (options.size === 0) {
this.remainingVerticesToInterfaceObjectOptions.delete(vertex);
}
}
for (const vertex of graph.allVertices()) {
if (vertex.source === querygraph_1.FEDERATED_GRAPH_ROOT_SOURCE
|| !(0, federation_internals_1.isCompositeType)(vertex.type)) {
continue;
}
const typeConditionName = vertex.type.name;
let endpointsEntry = this.inlineFragmentsToEndpoints
.get(typeConditionName);
if (!endpointsEntry) {
endpointsEntry = new Map();
this.inlineFragmentsToEndpoints.set(typeConditionName, endpointsEntry);
}
endpointsEntry.set(vertex, vertex);
if (!(0, federation_internals_1.isObjectType)(vertex.type)) {
continue;
}
const metadata = (0, federation_internals_1.federationMetadata)(vertex.type.schema());
(0, federation_internals_1.assert)(metadata, () => 'Subgraph schema unexpectedly did not have subgraph metadata');
if (metadata.isInterfaceObjectType(vertex.type)) {
continue;
}
let downcastsEntry = this.verticesToObjectTypeDowncasts.get(vertex);
if (!downcastsEntry) {
downcastsEntry = {
kind: 'NonInterfaceObject',
downcasts: new Map(),
};
this.verticesToObjectTypeDowncasts.set(vertex, downcastsEntry);
}
(0, federation_internals_1.assert)(downcastsEntry.kind === 'NonInterfaceObject', () => 'Unexpectedly found object type with interface object downcasts in supergraph');
downcastsEntry.downcasts.set(typeConditionName, vertex);
}
}
precomputeRebasingMetadata(graph) {
var _a;
const compositeTypesToVerticesBySource = new Map();
for (const vertex of graph.allVertices()) {
if (vertex.source === querygraph_1.FEDERATED_GRAPH_ROOT_SOURCE
|| !(0, federation_internals_1.isCompositeType)(vertex.type)) {
continue;
}
let typesToVerticesEntry = compositeTypesToVerticesBySource
.get(vertex.source);
if (!typesToVerticesEntry) {
typesToVerticesEntry = new Map();
compositeTypesToVerticesBySource.set(vertex.source, typesToVerticesEntry);
}
let verticesEntry = typesToVerticesEntry.get(vertex.type.name);
if (!verticesEntry) {
verticesEntry = new Set();
typesToVerticesEntry.set(vertex.type.name, verticesEntry);
}
verticesEntry.add(vertex);
}
for (const [source, schema] of graph.sources) {
if (source === querygraph_1.FEDERATED_GRAPH_ROOT_SOURCE) {
continue;
}
const fieldsToRebaseableTypes = new Map();
const objectTypesToImplementingCompositeTypes = new Map();
const metadata = (0, federation_internals_1.federationMetadata)(schema);
(0, federation_internals_1.assert)(metadata, () => 'Subgraph schema unexpectedly did not have subgraph metadata');
const fromContextDirectiveName = metadata.fromContextDirective().name;
for (const type of schema.types()) {
switch (type.kind) {
case 'ObjectType': {
for (const field of type.fields()) {
if (field.arguments().some((arg) => arg.hasAppliedDirective(fromContextDirectiveName))) {
continue;
}
let rebaseableTypesEntry = fieldsToRebaseableTypes.get(field.name);
if (!rebaseableTypesEntry) {
rebaseableTypesEntry = new Set();
fieldsToRebaseableTypes.set(field.name, rebaseableTypesEntry);
}
rebaseableTypesEntry.add(type.name);
}
let rebaseableTypesEntry = fieldsToRebaseableTypes.get(federation_internals_1.typenameFieldName);
if (!rebaseableTypesEntry) {
rebaseableTypesEntry = new Set();
fieldsToRebaseableTypes.set(federation_internals_1.typenameFieldName, rebaseableTypesEntry);
}
rebaseableTypesEntry.add(type.name);
let implementingObjectTypesEntry = objectTypesToImplementingCompositeTypes.get(type.name);
if (!implementingObjectTypesEntry) {
implementingObjectTypesEntry = new Set();
objectTypesToImplementingCompositeTypes.set(type.name, implementingObjectTypesEntry);
}
implementingObjectTypesEntry.add(type.name);
for (const interfaceImplementation of type.interfaceImplementations()) {
implementingObjectTypesEntry.add(interfaceImplementation.interface.name);
}
break;
}
case 'InterfaceType': {
for (const field of type.fields()) {
if (field.arguments().some((arg) => arg.hasAppliedDirective(fromContextDirectiveName))) {
continue;
}
let rebaseableTypesEntry = fieldsToRebaseableTypes.get(field.name);
if (!rebaseableTypesEntry) {
rebaseableTypesEntry = new Set();
fieldsToRebaseableTypes.set(field.name, rebaseableTypesEntry);
}
rebaseableTypesEntry.add(type.name);
}
let rebaseableTypesEntry = fieldsToRebaseableTypes.get(federation_internals_1.typenameFieldName);
if (!rebaseableTypesEntry) {
rebaseableTypesEntry = new Set();
fieldsToRebaseableTypes.set(federation_internals_1.typenameFieldName, rebaseableTypesEntry);
}
rebaseableTypesEntry.add(type.name);
break;
}
case 'UnionType': {
let rebaseableTypesEntry = fieldsToRebaseableTypes.get(federation_internals_1.typenameFieldName);
if (!rebaseableTypesEntry) {
rebaseableTypesEntry = new Set();
fieldsToRebaseableTypes.set(federation_internals_1.typenameFieldName, rebaseableTypesEntry);
}
rebaseableTypesEntry.add(type.name);
for (const member of type.members()) {
let implementingObjectTypesEntry = objectTypesToImplementingCompositeTypes.get(member.type.name);
if (!implementingObjectTypesEntry) {
implementingObjectTypesEntry = new Set();
objectTypesToImplementingCompositeTypes.set(member.type.name, implementingObjectTypesEntry);
}
implementingObjectTypesEntry.add(type.name);
}
break;
}
case 'ScalarType':
case 'EnumType':
case 'InputObjectType':
break;
default:
(0, federation_internals_1.assertUnreachable)(type);
}
}
const inlineFragmentsToRebaseableTypes = new Map();
for (const implementingTypes of objectTypesToImplementingCompositeTypes.values()) {
for (const typeName of implementingTypes) {
let rebaseableTypesEntry = inlineFragmentsToRebaseableTypes.get(typeName);
if (!rebaseableTypesEntry) {
rebaseableTypesEntry = new Set();
fieldsToRebaseableTypes.set(typeName, rebaseableTypesEntry);
}
for (const implementingType of implementingTypes) {
rebaseableTypesEntry.add(implementingType);
}
}
}
const compositeTypesToVertices = (_a = compositeTypesToVerticesBySource.get(source)) !== null && _a !== void 0 ? _a : new Map();
for (const [fieldName, types] of fieldsToRebaseableTypes) {
let rebaseableParentVerticesEntry = this.fieldsToRebaseableParentVertices.get(fieldName);
if (!rebaseableParentVerticesEntry) {
rebaseableParentVerticesEntry = new Set();
this.fieldsToRebaseableParentVertices.set(fieldName, rebaseableParentVerticesEntry);
}
for (const type of types) {
const vertices = compositeTypesToVertices.get(type);
if (vertices) {
for (const vertex of vertices) {
rebaseableParentVerticesEntry.add(vertex);
}
}
}
}
for (const [typeConditionName, types] of inlineFragmentsToRebaseableTypes) {
let rebaseableParentVerticesEntry = this.inlineFragmentsToRebaseableParentVertices.get(typeConditionName);
if (!rebaseableParentVerticesEntry) {
rebaseableParentVerticesEntry = new Set();
this.inlineFragmentsToRebaseableParentVertices.set(typeConditionName, rebaseableParentVerticesEntry);
}
for (const type of types) {
const vertices = compositeTypesToVertices.get(type);
if (vertices) {
for (const vertex of vertices) {
rebaseableParentVerticesEntry.add(vertex);
}
}
}
}
}
}
checkNonLocalSelectionsLimitExceededAtRoot(stack, state, supergraphSchema, inconsistentAbstractTypesRuntimes, overrideConditions) {
for (const [selection, simultaneousPaths] of stack) {
const tailVertices = new Set();
for (const simultaneousPath of simultaneousPaths) {
for (const path of simultaneousPath.paths) {
tailVertices.add(path.tail);
}
}
const tailVerticesInfo = this.estimateVerticesWithIndirectOptions(tailVertices);
if (this.updateCount(1, tailVertices.size, state)) {
return true;
}
if (selection.selectionSet) {
const selectionHasDefer = selection.hasDefer();
const nextVertices = this.estimateNextVerticesForSelection(selection.element, tailVerticesInfo, state, supergraphSchema, overrideConditions);
if (this.checkNonLocalSelectionsLimitExceeded(selection.selectionSet, nextVertices, selectionHasDefer, state, supergraphSchema, inconsistentAbstractTypesRuntimes, overrideConditions)) {
return true;
}
}
}
return false;
}
checkNonLocalSelectionsLimitExceeded(selectionSet, parentVertices, parentSelectionHasDefer, state, supergraphSchema, inconsistentAbstractTypesRuntimes, overrideConditions) {
var _a;
let selectionSetIsNonLocal = parentVertices.nextVerticesHaveReachableCrossSubgraphEdges
|| parentSelectionHasDefer;
for (const selection of selectionSet.selections()) {
const element = selection.element;
const selectionHasDefer = element.hasDefer();
const selectionHasInconsistentRuntimeTypes = element.kind === 'FragmentElement'
&& element.typeCondition
&& inconsistentAbstractTypesRuntimes.has(element.typeCondition.name);
const oldCount = state.count;
if (selection.selectionSet) {
const nextVertices = this.estimateNextVerticesForSelection(element, parentVertices, state, supergraphSchema, overrideConditions);
if (this.checkNonLocalSelectionsLimitExceeded(selection.selectionSet, nextVertices, selectionHasDefer, state, supergraphSchema, inconsistentAbstractTypesRuntimes, overrideConditions)) {
return true;
}
}
selectionSetIsNonLocal || (selectionSetIsNonLocal = selectionHasDefer
|| selectionHasInconsistentRuntimeTypes
|| (oldCount != state.count));
}
if (!selectionSetIsNonLocal && parentVertices.nextVertices.size > 0) {
outer: for (const selection of selectionSet.selections()) {
switch (selection.kind) {
case 'FieldSelection': {
const rebaseableParentVertices = this.fieldsToRebaseableParentVertices
.get(selection.element.definition.name);
if (!rebaseableParentVertices) {
selectionSetIsNonLocal = true;
break outer;
}
for (const vertex of parentVertices.nextVertices) {
if (!rebaseableParentVertices.has(vertex)) {
selectionSetIsNonLocal = true;
break outer;
}
}
break;
}
case 'FragmentSelection': {
const typeConditionName = (_a = selection.element.typeCondition) === null || _a === void 0 ? void 0 : _a.name;
if (!typeConditionName) {
continue;
}
const rebaseableParentVertices = this.inlineFragmentsToRebaseableParentVertices
.get(typeConditionName);
if (!rebaseableParentVertices) {
selectionSetIsNonLocal = true;
break outer;
}
for (const vertex of parentVertices.nextVertices) {
if (!rebaseableParentVertices.has(vertex)) {
selectionSetIsNonLocal = true;
break outer;
}
}
break;
}
default:
(0, federation_internals_1.assertUnreachable)(selection);
}
}
}
return selectionSetIsNonLocal && this.updateCount(selectionSet.selections().length, parentVertices.nextVertices.size, state);
}
updateCount(numSelections, numParentVertices, state) {
const additional_count = numSelections * numParentVertices;
const new_count = state.count + additional_count;
if (new_count > NonLocalSelectionsMetadata.MAX_NON_LOCAL_SELECTIONS) {
return true;
}
state.count = new_count;
return false;
}
estimateNextVerticesForSelection(element, parentVertices, state, supergraphSchema, overrideConditions) {
var _a;
const selectionKey = element.kind === 'Field'
? element.definition.name
: (_a = element.typeCondition) === null || _a === void 0 ? void 0 : _a.name;
if (!selectionKey) {
return parentVertices;
}
let cache = state.nextVerticesCache.get(selectionKey);
if (!cache) {
cache = {
typesToNextVertices: new Map(),
remainingVerticesToNextVertices: new Map(),
};
state.nextVerticesCache.set(selectionKey, cache);
}
const nextVerticesInfo = {
nextVertices: new Set(),
nextVerticesHaveReachableCrossSubgraphEdges: false,
nextVerticesWithIndirectOptions: {
types: new Set(),
remainingVertices: new Set(),
}
};
for (const typeName of parentVertices.nextVerticesWithIndirectOptions.types) {
let cacheEntry = cache.typesToNextVertices.get(typeName);
if (!cacheEntry) {
const indirectOptions = this.typesToIndirectOptions.get(typeName);
(0, federation_internals_1.assert)(indirectOptions, () => 'Unexpectedly missing vertex information for cached type');
cacheEntry = this.estimateNextVerticesForSelectionWithoutCaching(element, indirectOptions.sameTypeOptions, supergraphSchema, overrideConditions);
cache.typesToNextVertices.set(typeName, cacheEntry);
}
this.mergeNextVerticesInfo(cacheEntry, nextVerticesInfo);
}
for (const vertex of parentVertices.nextVerticesWithIndirectOptions.remainingVertices) {
let cacheEntry = cache.remainingVerticesToNextVertices.get(vertex);
if (!cacheEntry) {
cacheEntry = this.estimateNextVerticesForSelectionWithoutCaching(element, [vertex], supergraphSchema, overrideConditions);
cache.remainingVerticesToNextVertices.set(vertex, cacheEntry);
}
this.mergeNextVerticesInfo(cacheEntry, nextVerticesInfo);
}
return nextVerticesInfo;
}
mergeNextVerticesInfo(source, target) {
for (const vertex of source.nextVertices) {
target.nextVertices.add(vertex);
}
target.nextVerticesHaveReachableCrossSubgraphEdges || (target.nextVerticesHaveReachableCrossSubgraphEdges = source.nextVerticesHaveReachableCrossSubgraphEdges);
this.mergeVerticesWithIndirectOptionsInfo(source.nextVerticesWithIndirectOptions, target.nextVerticesWithIndirectOptions);
}
mergeVerticesWithIndirectOptionsInfo(source, target) {
for (const type of source.types) {
target.types.add(type);
}
for (const vertex of source.remainingVertices) {
target.remainingVertices.add(vertex);
}
}
estimateNextVerticesForSelectionWithoutCaching(element, parentVertices, supergraphSchema, overrideConditions) {
var _a;
const nextVertices = new Set();
switch (element.kind) {
case 'Field': {
const fieldEndpoints = this.fieldsToEndpoints
.get(element.definition.name);
const processHeadVertex = (vertex) => {
const fieldTail = fieldEndpoints === null || fieldEndpoints === void 0 ? void 0 : fieldEndpoints.get(vertex);
if (!fieldTail) {
return;
}
if (fieldTail.overrideCondition) {
if ((0, querygraph_1.checkOverrideCondition)(fieldTail.overrideCondition, overrideConditions)) {
nextVertices.add(fieldTail.tail);
}
}
else {
nextVertices.add(fieldTail.tail);
}
};
for (const vertex of parentVertices) {
processHeadVertex(vertex);
const downcasts = this.verticesToObjectTypeDowncasts.get(vertex);
if (!downcasts) {
continue;
}
if (downcasts.kind === 'NonInterfaceObject') {
for (const vertex of downcasts.downcasts.values()) {
processHeadVertex(vertex);
}
}
}
break;
}
case 'FragmentElement': {
const typeConditionName = (_a = element.typeCondition) === null || _a === void 0 ? void 0 : _a.name;
(0, federation_internals_1.assert)(typeConditionName, () => 'Inline fragment unexpectedly had no type condition');
const inlineFragmentEndpoints = this.inlineFragmentsToEndpoints
.get(typeConditionName);
let runtimeTypes = null;
for (const vertex of parentVertices) {
const nextVertex = inlineFragmentEndpoints === null || inlineFragmentEndpoints === void 0 ? void 0 : inlineFragmentEndpoints.get(vertex);
if (nextVertex) {
nextVertices.add(nextVertex);
continue;
}
const downcasts = this.verticesToObjectTypeDowncasts.get(vertex);
if (!downcasts) {
continue;
}
if (!runtimeTypes) {
const typeInSupergraph = supergraphSchema.type(typeConditionName);
(0, federation_internals_1.assert)(typeInSupergraph && (0, federation_internals_1.isCompositeType)(typeInSupergraph), () => 'Type unexpectedly missing or non-composite in supergraph schema');
runtimeTypes = new Set();
for (const type of (0, federation_internals_1.possibleRuntimeTypes)(typeInSupergraph)) {
runtimeTypes.add(type.name);
}
}
switch (downcasts.kind) {
case 'NonInterfaceObject': {
for (const [typeName, vertex] of downcasts.downcasts) {
if (runtimeTypes.has(typeName)) {
nextVertices.add(vertex);
}
}
break;
}
case 'InterfaceObject': {
for (const typeName of downcasts.downcasts) {
if (runtimeTypes.has(typeName)) {
nextVertices.add(vertex);
break;
}
}
break;
}
default:
(0, federation_internals_1.assertUnreachable)(downcasts);
}
}
break;
}
default:
(0, federation_internals_1.assertUnreachable)(element);
}
return this.estimateVerticesWithIndirectOptions(nextVertices);
}
estimateVerticesWithIndirectOptions(nextVertices) {
const nextVerticesInfo = {
nextVertices,
nextVerticesHaveReachableCrossSubgraphEdges: false,
nextVerticesWithIndirectOptions: {
types: new Set(),
remainingVertices: new Set(),
}
};
for (const nextVertex of nextVertices) {
nextVerticesInfo.nextVerticesHaveReachableCrossSubgraphEdges || (nextVerticesInfo.nextVerticesHaveReachableCrossSubgraphEdges = nextVertex.hasReachableCrossSubgraphEdges);
const typeName = nextVertex.type.name;
const optionsMetadata = this.typesToIndirectOptions.get(typeName);
if (optionsMetadata) {
if (!nextVerticesInfo.nextVerticesWithIndirectOptions.types.has(typeName)) {
nextVerticesInfo.nextVerticesWithIndirectOptions.types.add(typeName);
for (const option of optionsMetadata.interfaceObjectOptions) {
nextVerticesInfo.nextVerticesWithIndirectOptions.types.add(option);
}
}
if (optionsMetadata.sameTypeOptions.has(nextVertex)) {
continue;
}
}
if (!nextVerticesInfo.nextVerticesWithIndirectOptions.remainingVertices
.has(nextVertex)) {
nextVerticesInfo.nextVerticesWithIndirectOptions.remainingVertices
.add(nextVertex);
const options = this.remainingVerticesToInterfaceObjectOptions
.get(nextVertex);
if (options) {
for (const option of options) {
nextVerticesInfo.nextVerticesWithIndirectOptions.types.add(option);
}
}
}
}
return nextVerticesInfo;
}
}
exports.NonLocalSelectionsMetadata = NonLocalSelectionsMetadata;
NonLocalSelectionsMetadata.MAX_NON_LOCAL_SELECTIONS = 100000;
class NonLocalSelectionsState {
constructor() {
this.count = 0;
this.nextVerticesCache = new Map;
}
}
exports.NonLocalSelectionsState = NonLocalSelectionsState;
//# sourceMappingURL=nonLocalSelectionsEstimation.js.map