@graphql-tools/executor 4.1.1 → 4.1.2-alpha-20261020170708-72d61a1bbfbf64a0a9d61e801c80001b7ea79dc3

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.
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.collectIncrementalFields = collectIncrementalFields;
4
+ exports.collectIncrementalSubfields = collectIncrementalSubfields;
5
+ exports.buildExecutionPlan = buildExecutionPlan;
6
+ exports.deferUsageForFieldNode = deferUsageForFieldNode;
7
+ exports.groupedFieldSetToFieldMap = groupedFieldSetToFieldMap;
8
+ exports.rootDeferUsage = rootDeferUsage;
9
+ exports.labelForDeferUsageSet = labelForDeferUsageSet;
10
+ const graphql_1 = require("graphql");
11
+ const utils_1 = require("@graphql-tools/utils");
12
+ const getBySet_js_1 = require("./getBySet.js");
13
+ const isSameSet_js_1 = require("./isSameSet.js");
14
+ class FieldDetailsMap extends Map {
15
+ add(key, item) {
16
+ const group = this.get(key);
17
+ if (group === undefined) {
18
+ this.set(key, [item]);
19
+ }
20
+ else {
21
+ group.push(item);
22
+ }
23
+ }
24
+ }
25
+ function collectIncrementalFields(schema, fragments, variableValues, runtimeType, selectionSet, parentDeferUsage) {
26
+ const groupedFieldSet = new FieldDetailsMap();
27
+ const newDeferUsages = [];
28
+ const context = {
29
+ schema,
30
+ fragments,
31
+ variableValues,
32
+ runtimeType,
33
+ visitedFragmentNames: new Map(),
34
+ };
35
+ collectFieldsImpl(context, selectionSet, groupedFieldSet, newDeferUsages, parentDeferUsage);
36
+ return { groupedFieldSet, newDeferUsages };
37
+ }
38
+ const deferUsageByFieldNode = new WeakMap();
39
+ function collectIncrementalSubfields(schema, fragments, variableValues, returnType, fieldNodes, parentDeferUsage) {
40
+ const groupedFieldSet = new FieldDetailsMap();
41
+ const newDeferUsages = [];
42
+ const context = {
43
+ schema,
44
+ fragments,
45
+ variableValues,
46
+ runtimeType: returnType,
47
+ visitedFragmentNames: new Map(),
48
+ };
49
+ for (const node of fieldNodes) {
50
+ if (node.selectionSet) {
51
+ const deferUsage = deferUsageByFieldNode.has(node)
52
+ ? deferUsageByFieldNode.get(node)
53
+ : parentDeferUsage;
54
+ collectFieldsImpl(context, node.selectionSet, groupedFieldSet, newDeferUsages, deferUsage);
55
+ }
56
+ }
57
+ return { groupedFieldSet, newDeferUsages };
58
+ }
59
+ function collectFieldsImpl(context, selectionSet, groupedFieldSet, newDeferUsages, deferUsage) {
60
+ const { schema, fragments, variableValues, runtimeType, visitedFragmentNames } = context;
61
+ for (const selection of selectionSet.selections) {
62
+ switch (selection.kind) {
63
+ case graphql_1.Kind.FIELD: {
64
+ if (!(0, utils_1.shouldIncludeNode)(variableValues, selection)) {
65
+ continue;
66
+ }
67
+ groupedFieldSet.add((0, utils_1.getFieldEntryKey)(selection), {
68
+ node: selection,
69
+ deferUsage,
70
+ });
71
+ break;
72
+ }
73
+ case graphql_1.Kind.INLINE_FRAGMENT: {
74
+ if (!(0, utils_1.shouldIncludeNode)(variableValues, selection) ||
75
+ !(0, utils_1.doesFragmentConditionMatch)(schema, selection, runtimeType)) {
76
+ continue;
77
+ }
78
+ const newDeferUsage = getDeferUsage(variableValues, selection, deferUsage);
79
+ if (!newDeferUsage) {
80
+ collectFieldsImpl(context, selection.selectionSet, groupedFieldSet, newDeferUsages, deferUsage);
81
+ }
82
+ else {
83
+ newDeferUsages.push(newDeferUsage);
84
+ collectFieldsImpl(context, selection.selectionSet, groupedFieldSet, newDeferUsages, newDeferUsage);
85
+ }
86
+ break;
87
+ }
88
+ case graphql_1.Kind.FRAGMENT_SPREAD: {
89
+ const fragName = selection.name.value;
90
+ if (!(0, utils_1.shouldIncludeNode)(variableValues, selection)) {
91
+ continue;
92
+ }
93
+ const fragment = fragments[fragName];
94
+ if (!fragment || !(0, utils_1.doesFragmentConditionMatch)(schema, fragment, runtimeType)) {
95
+ continue;
96
+ }
97
+ const newDeferUsage = getDeferUsage(variableValues, selection, deferUsage);
98
+ const visitedAsDeferred = visitedFragmentNames.get(fragName);
99
+ let maybeNewDeferUsage;
100
+ if (!newDeferUsage) {
101
+ if (visitedAsDeferred === false) {
102
+ continue;
103
+ }
104
+ visitedFragmentNames.set(fragName, false);
105
+ maybeNewDeferUsage = deferUsage;
106
+ }
107
+ else {
108
+ if (visitedAsDeferred !== undefined) {
109
+ continue;
110
+ }
111
+ visitedFragmentNames.set(fragName, true);
112
+ newDeferUsages.push(newDeferUsage);
113
+ maybeNewDeferUsage = newDeferUsage;
114
+ }
115
+ collectFieldsImpl(context, fragment.selectionSet, groupedFieldSet, newDeferUsages, maybeNewDeferUsage);
116
+ break;
117
+ }
118
+ }
119
+ }
120
+ }
121
+ function getDeferUsage(variableValues, node, parentDeferUsage) {
122
+ const defer = (0, utils_1.getDirectiveValues)(utils_1.GraphQLDeferDirective, node, variableValues);
123
+ if (!defer || defer['if'] === false) {
124
+ return;
125
+ }
126
+ return {
127
+ label: typeof defer['label'] === 'string' ? defer['label'] : undefined,
128
+ parentDeferUsage,
129
+ };
130
+ }
131
+ function buildExecutionPlan(originalGroupedFieldSet, parentDeferUsages = new Set()) {
132
+ const groupedFieldSet = new Map();
133
+ const newGroupedFieldSets = new Map();
134
+ for (const [responseKey, fieldDetailsList] of originalGroupedFieldSet) {
135
+ const filteredDeferUsageSet = getFilteredDeferUsageSet(fieldDetailsList);
136
+ if ((0, isSameSet_js_1.isSameSet)(filteredDeferUsageSet, parentDeferUsages)) {
137
+ groupedFieldSet.set(responseKey, fieldDetailsList);
138
+ continue;
139
+ }
140
+ let newGroupedFieldSet = (0, getBySet_js_1.getBySet)(newGroupedFieldSets, filteredDeferUsageSet);
141
+ if (newGroupedFieldSet === undefined) {
142
+ newGroupedFieldSet = new Map();
143
+ newGroupedFieldSets.set(filteredDeferUsageSet, newGroupedFieldSet);
144
+ }
145
+ newGroupedFieldSet.set(responseKey, fieldDetailsList);
146
+ }
147
+ return { groupedFieldSet, newGroupedFieldSets };
148
+ }
149
+ function getFilteredDeferUsageSet(fieldDetailsList) {
150
+ const filteredDeferUsageSet = new Set();
151
+ for (const fieldDetails of fieldDetailsList) {
152
+ const deferUsage = fieldDetails.deferUsage;
153
+ if (deferUsage === undefined) {
154
+ filteredDeferUsageSet.clear();
155
+ return filteredDeferUsageSet;
156
+ }
157
+ filteredDeferUsageSet.add(deferUsage);
158
+ }
159
+ for (const deferUsage of filteredDeferUsageSet) {
160
+ let parentDeferUsage = deferUsage.parentDeferUsage;
161
+ while (parentDeferUsage !== undefined) {
162
+ if (filteredDeferUsageSet.has(parentDeferUsage)) {
163
+ filteredDeferUsageSet.delete(deferUsage);
164
+ break;
165
+ }
166
+ parentDeferUsage = parentDeferUsage.parentDeferUsage;
167
+ }
168
+ }
169
+ return filteredDeferUsageSet;
170
+ }
171
+ function deferUsageForFieldNode(node) {
172
+ return deferUsageByFieldNode.get(node);
173
+ }
174
+ function groupedFieldSetToFieldMap(groupedFieldSet) {
175
+ const fields = new Map();
176
+ for (const [responseKey, fieldDetailsList] of groupedFieldSet) {
177
+ fields.set(responseKey, fieldDetailsList.map(details => {
178
+ deferUsageByFieldNode.set(details.node, details.deferUsage);
179
+ return details.node;
180
+ }));
181
+ }
182
+ return fields;
183
+ }
184
+ function rootDeferUsage(deferUsageSet) {
185
+ for (const usage of deferUsageSet) {
186
+ if (usage.parentDeferUsage == null || !deferUsageSet.has(usage.parentDeferUsage)) {
187
+ return usage;
188
+ }
189
+ }
190
+ return undefined;
191
+ }
192
+ function labelForDeferUsageSet(deferUsageSet) {
193
+ return rootDeferUsage(deferUsageSet)?.label;
194
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isSameSet = isSameSet;
4
+ /** @internal */
5
+ function isSameSet(setA, setB) {
6
+ if (setA.size !== setB.size) {
7
+ return false;
8
+ }
9
+ for (const item of setA) {
10
+ if (!setB.has(item)) {
11
+ return false;
12
+ }
13
+ }
14
+ return true;
15
+ }
@@ -1,12 +1,14 @@
1
- import { assertValidSchema, getArgumentValues, getVariableValues, GraphQLError, isAbstractType, isLeafType, isListType, isNonNullType, isObjectType, Kind, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, versionInfo, } from 'graphql';
1
+ import { assertValidSchema, defaultFieldResolver, defaultTypeResolver, getArgumentValues, getVariableValues, GraphQLError, isAbstractType, isLeafType, isListType, isNonNullType, isObjectType, Kind, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, versionInfo, } from 'graphql';
2
2
  import { collectSubFields as _collectSubfields, addPath, collectFields, getDefinedRootType, getDirectiveValues, GraphQLStreamDirective, inspect, isAsyncIterable, isIterableObject, isObjectLike, locatedError, memoize2, memoize3, pathToArray, promiseReduce, } from '@graphql-tools/utils';
3
3
  import { DisposableSymbols } from '@whatwg-node/disposablestack';
4
4
  import { fakePromise, handleMaybePromise, isPromise, mapAsyncIterator, } from '@whatwg-node/promise-helpers';
5
5
  import { coerceError } from './coerceError.js';
6
6
  import { flattenAsyncIterable } from './flattenAsyncIterable.js';
7
- import { collectInitialPending, createIncrementalPublisherState, createStreamGroupIfV02, DeferredFragmentRecord, deleteAsyncPayload, isStreamPayload, StreamRecord, yieldSubsequentPayloads, } from './incremental.js';
7
+ import { cancelAsyncPayload, collectInitialPending, createIncrementalPublisherState, createStreamGroupIfV02, DeferredFragmentRecord, isAtOrUnderNulledPath, pathStartsWith, StreamRecord, yieldSubsequentPayloads, } from './incremental.js';
8
+ import { buildExecutionPlan, collectIncrementalFields, collectIncrementalSubfields, deferUsageForFieldNode, groupedFieldSetToFieldMap, labelForDeferUsageSet, rootDeferUsage, } from './incrementalCollect.js';
8
9
  import { invariant } from './invariant.js';
9
10
  import { promiseForObject } from './promiseForObject.js';
11
+ export { defaultFieldResolver, defaultTypeResolver };
10
12
  const EMPTY_ARGS = Object.freeze(Object.create(null));
11
13
  const isGraphQL17 = versionInfo.major >= 17;
12
14
  /**
@@ -387,18 +389,52 @@ function executeOperation(exeContext) {
387
389
  const { fields: rootFields, patches } = collectFields(schema, fragments, variableValues, rootType, operation.selectionSet);
388
390
  const path = undefined;
389
391
  let result;
392
+ if (patches.length === 0) {
393
+ if (operation.operation === 'mutation') {
394
+ result = executeFieldsSerially(exeContext, rootType, rootValue, path, rootFields);
395
+ }
396
+ else {
397
+ result = executeFields(exeContext, rootType, rootValue, path, rootFields);
398
+ }
399
+ return result;
400
+ }
401
+ exeContext.nulledPaths ??= [];
402
+ const { groupedFieldSet } = collectIncrementalFields(schema, fragments, variableValues, rootType, operation.selectionSet);
403
+ const { groupedFieldSet: initialFields, newGroupedFieldSets } = buildExecutionPlan(groupedFieldSet);
404
+ const plannedRootFields = groupedFieldSetToFieldMap(initialFields);
390
405
  if (operation.operation === 'mutation') {
391
- result = executeFieldsSerially(exeContext, rootType, rootValue, path, rootFields);
406
+ result = executeFieldsSerially(exeContext, rootType, rootValue, path, plannedRootFields);
392
407
  }
393
408
  else {
394
- result = executeFields(exeContext, rootType, rootValue, path, rootFields);
395
- }
396
- for (const patch of patches) {
397
- const { label, fields: patchFields, patches: nestedPatches } = patch;
398
- executeDeferredFragment(exeContext, rootType, rootValue, patchFields, label, path, undefined, nestedPatches);
409
+ result = executeFields(exeContext, rootType, rootValue, path, plannedRootFields);
399
410
  }
411
+ executeDeferredGroups(exeContext, rootType, rootValue, path, newGroupedFieldSets, undefined);
400
412
  return result;
401
413
  }
414
+ function executeDeferredGroups(exeContext, parentType, sourceValue, path, newGroupedFieldSets, parentContext) {
415
+ if (isAtOrUnderNulledPath(pathToArray(path), exeContext.nulledPaths)) {
416
+ return;
417
+ }
418
+ const records = new Map();
419
+ const groups = [...newGroupedFieldSets.entries()].sort(([a], [b]) => deferUsageDepth(rootDeferUsage(a)) - deferUsageDepth(rootDeferUsage(b)));
420
+ for (const [deferUsageSet, groupedFieldSet] of groups) {
421
+ const usage = rootDeferUsage(deferUsageSet);
422
+ const deliveryParent = (usage?.parentDeferUsage && records.get(usage.parentDeferUsage)) ?? parentContext;
423
+ const record = executeDeferredFragment(exeContext, parentType, sourceValue, groupedFieldSetToFieldMap(groupedFieldSet), labelForDeferUsageSet(deferUsageSet), path, parentContext, undefined, deliveryParent, usage);
424
+ if (usage) {
425
+ records.set(usage, record);
426
+ }
427
+ }
428
+ }
429
+ function deferUsageDepth(usage) {
430
+ let depth = 0;
431
+ let current = usage;
432
+ while (current?.parentDeferUsage) {
433
+ depth++;
434
+ current = current.parentDeferUsage;
435
+ }
436
+ return depth;
437
+ }
402
438
  /**
403
439
  * Implements the "Executing selection sets" section of the spec
404
440
  * for fields that must be executed serially.
@@ -872,69 +908,29 @@ function invalidReturnTypeError(returnType, result, fieldNodes) {
872
908
  function collectAndExecuteSubfields(exeContext, returnType, fieldNodes, path, result, asyncPayloadRecord) {
873
909
  // Collect sub-fields to execute to complete this value.
874
910
  const { fields: subFieldNodes, patches: subPatches } = collectSubfields(exeContext, returnType, fieldNodes);
875
- const subFields = executeFields(exeContext, returnType, result, path, subFieldNodes, asyncPayloadRecord);
876
- for (const subPatch of subPatches) {
877
- const { label, fields: subPatchFieldNodes, patches: nestedPatches } = subPatch;
878
- executeDeferredFragment(exeContext, returnType, result, subPatchFieldNodes, label, path, asyncPayloadRecord, nestedPatches);
879
- }
880
- return subFields;
881
- }
882
- /**
883
- * If a resolveType function is not given, then a default resolve behavior is
884
- * used which attempts two strategies:
885
- *
886
- * First, See if the provided value has a `__typename` field defined, if so, use
887
- * that value as name of the resolved type.
888
- *
889
- * Otherwise, test each possible type for the abstract type by calling
890
- * isTypeOf for the object being coerced, returning the first type that matches.
891
- */
892
- export const defaultTypeResolver = function (value, contextValue, info, abstractType) {
893
- // First, look for `__typename`.
894
- if (isObjectLike(value) && typeof value['__typename'] === 'string') {
895
- return value['__typename'];
896
- }
897
- // Otherwise, test each possible type.
898
- const possibleTypes = info.schema.getPossibleTypes(abstractType);
899
- const promisedIsTypeOfResults = [];
900
- for (let i = 0; i < possibleTypes.length; i++) {
901
- const type = possibleTypes[i];
902
- if (type.isTypeOf) {
903
- const isTypeOfResult = type.isTypeOf(value, contextValue, info);
904
- if (isPromise(isTypeOfResult)) {
905
- promisedIsTypeOfResults[i] = isTypeOfResult;
906
- }
907
- else if (isTypeOfResult) {
908
- return type.name;
909
- }
910
- }
911
- }
912
- if (promisedIsTypeOfResults.length) {
913
- return Promise.all(promisedIsTypeOfResults).then(isTypeOfResults => {
914
- for (let i = 0; i < isTypeOfResults.length; i++) {
915
- if (isTypeOfResults[i]) {
916
- return possibleTypes[i].name;
917
- }
911
+ if (subPatches.length === 0 && exeContext.nulledPaths == null) {
912
+ return executeFields(exeContext, returnType, result, path, subFieldNodes, asyncPayloadRecord);
913
+ }
914
+ exeContext.nulledPaths ??= [];
915
+ const parentDeferUsage = asyncPayloadRecord?.type === 'defer' ? asyncPayloadRecord.deferUsage : undefined;
916
+ const { groupedFieldSet } = collectIncrementalSubfields(exeContext.schema, exeContext.fragments, exeContext.variableValues, returnType, fieldNodes, parentDeferUsage);
917
+ const parentDeferUsages = new Set();
918
+ if (parentDeferUsage) {
919
+ parentDeferUsages.add(parentDeferUsage);
920
+ }
921
+ else if (asyncPayloadRecord?.type === 'stream') {
922
+ for (const node of fieldNodes) {
923
+ const usage = deferUsageForFieldNode(node);
924
+ if (usage) {
925
+ parentDeferUsages.add(usage);
918
926
  }
919
- });
920
- }
921
- };
922
- /**
923
- * If a resolve function is not given, then a default resolve behavior is used
924
- * which takes the property of the source object of the same name as the field
925
- * and returns it as the result, or if it's a function, returns the result
926
- * of calling that function while passing along args and context value.
927
- */
928
- export const defaultFieldResolver = function (source, args, contextValue, info) {
929
- // ensure source is a value for which property access is acceptable.
930
- if (isObjectLike(source) || typeof source === 'function') {
931
- const property = source[info.fieldName];
932
- if (typeof property === 'function') {
933
- return source[info.fieldName](args, contextValue, info);
934
927
  }
935
- return property;
936
928
  }
937
- };
929
+ const { groupedFieldSet: initialFields, newGroupedFieldSets } = buildExecutionPlan(groupedFieldSet, parentDeferUsages);
930
+ const subFields = executeFields(exeContext, returnType, result, path, groupedFieldSetToFieldMap(initialFields), asyncPayloadRecord);
931
+ executeDeferredGroups(exeContext, returnType, result, path, newGroupedFieldSets, asyncPayloadRecord);
932
+ return subFields;
933
+ }
938
934
  /**
939
935
  * Implements the "Subscribe" algorithm described in the GraphQL specification,
940
936
  * including `@defer` and `@stream` as proposed in
@@ -1142,13 +1138,14 @@ function assertEventStream(result, signal, onSignalAbort) {
1142
1138
  }
1143
1139
  return result;
1144
1140
  }
1145
- function executeDeferredFragment(exeContext, parentType, sourceValue, fields, label, path, parentContext, nestedPatches, deliveryParent) {
1141
+ function executeDeferredFragment(exeContext, parentType, sourceValue, fields, label, path, parentContext, nestedPatches, deliveryParent, deferUsage) {
1146
1142
  const asyncPayloadRecord = new DeferredFragmentRecord({
1147
1143
  label,
1148
1144
  path,
1149
1145
  parentContext,
1150
1146
  deliveryParent: deliveryParent ?? parentContext,
1151
1147
  exeContext,
1148
+ deferUsage,
1152
1149
  });
1153
1150
  let promiseOrData;
1154
1151
  try {
@@ -1172,6 +1169,7 @@ function executeDeferredFragment(exeContext, parentType, sourceValue, fields, la
1172
1169
  parentContext, nested.patches, asyncPayloadRecord);
1173
1170
  }
1174
1171
  }
1172
+ return asyncPayloadRecord;
1175
1173
  }
1176
1174
  function executeStreamField(path, itemPath, item, exeContext, fieldNodes, info, itemType, label, parentContext, streamGroup) {
1177
1175
  const asyncPayloadRecord = new StreamRecord({
@@ -1181,6 +1179,10 @@ function executeStreamField(path, itemPath, item, exeContext, fieldNodes, info,
1181
1179
  exeContext,
1182
1180
  streamGroup,
1183
1181
  });
1182
+ if (isAtOrUnderNulledPath(asyncPayloadRecord.path, exeContext.nulledPaths)) {
1183
+ cancelAsyncPayload(exeContext, asyncPayloadRecord);
1184
+ return asyncPayloadRecord;
1185
+ }
1184
1186
  let completedItem;
1185
1187
  try {
1186
1188
  try {
@@ -1283,6 +1285,15 @@ async function executeStreamIterator(initialIndex, iterator, exeContext, fieldNo
1283
1285
  exeContext,
1284
1286
  streamGroup,
1285
1287
  });
1288
+ if (isAtOrUnderNulledPath(asyncPayloadRecord.path, exeContext.nulledPaths)) {
1289
+ cancelAsyncPayload(exeContext, asyncPayloadRecord);
1290
+ if (iterator.return) {
1291
+ iterator.return().catch(() => {
1292
+ // ignore errors
1293
+ });
1294
+ }
1295
+ break;
1296
+ }
1286
1297
  let iteration;
1287
1298
  try {
1288
1299
  iteration = await executeStreamIteratorItem(iterator, exeContext, fieldNodes, info, itemType, asyncPayloadRecord, itemPath);
@@ -1324,24 +1335,22 @@ async function executeStreamIterator(initialIndex, iterator, exeContext, fieldNo
1324
1335
  }
1325
1336
  function filterSubsequentPayloads(exeContext, nullPath, currentAsyncRecord) {
1326
1337
  const nullPathArray = pathToArray(nullPath);
1338
+ if (exeContext.nulledPaths) {
1339
+ exeContext.nulledPaths.push(nullPathArray);
1340
+ }
1341
+ else if (exeContext.subsequentPayloads.size === 0) {
1342
+ return;
1343
+ }
1327
1344
  exeContext.subsequentPayloads.forEach(asyncRecord => {
1328
- if (asyncRecord === currentAsyncRecord) {
1345
+ if (asyncRecord === currentAsyncRecord || asyncRecord.cancelled) {
1329
1346
  // don't remove payload from where error originates
1330
1347
  return;
1331
1348
  }
1332
- for (let i = 0; i < nullPathArray.length; i++) {
1333
- if (asyncRecord.path[i] !== nullPathArray[i]) {
1334
- // asyncRecord points to a path unaffected by this payload
1335
- return;
1336
- }
1337
- }
1338
- // asyncRecord path points to nulled error field
1339
- if (isStreamPayload(asyncRecord) && asyncRecord.iterator?.return) {
1340
- asyncRecord.iterator.return().catch(() => {
1341
- // ignore error
1342
- });
1349
+ if (!pathStartsWith(asyncRecord.path, nullPathArray)) {
1350
+ // ancestor or a different branch: ancestor patches are pruned at yield
1351
+ return;
1343
1352
  }
1344
- deleteAsyncPayload(exeContext, asyncRecord);
1353
+ cancelAsyncPayload(exeContext, asyncRecord);
1345
1354
  });
1346
1355
  }
1347
1356
  /**
@@ -0,0 +1,10 @@
1
+ import { isSameSet } from './isSameSet.js';
2
+ /** @internal */
3
+ export function getBySet(map, setToMatch) {
4
+ for (const set of map.keys()) {
5
+ if (isSameSet(set, setToMatch)) {
6
+ return map.get(set);
7
+ }
8
+ }
9
+ return undefined;
10
+ }